You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3:为参数类型转换装饰器添加正确的类型提示

解决方案

要实现保留原函数参数数量、将所有参数类型改为Any且保留原返回类型的装饰器类型提示,需要结合ParamSpec和对应Python版本的类型扩展语法。

代码实现(Python 3.12+)

from typing import Callable, ParamSpec, TypeVar, Any
import inspect

P = ParamSpec("P")
R = TypeVar("R")

def coerce_args(func: Callable[P, R]) -> Callable[P[Any, ...], R]:
    """将函数参数强制转换为其类型提示指定的类型"""
    sig = inspect.signature(func)
    param_types = {
        name: param.annotation
        for name, param in sig.parameters.items()
        if param.annotation is not inspect.Parameter.empty
    }

    def wrapper(*args: Any, **kwargs: Any) -> R:
        # 绑定参数并应用默认值
        bound_args = sig.bind(*args, **kwargs)
        bound_args.apply_defaults()
        
        # 转换参数类型
        for name, value in bound_args.arguments.items():
            if name in param_types:
                bound_args.arguments[name] = param_types[name](value)
        
        return func(*bound_args.args, **bound_args.kwargs)
    
    return wrapper

# 测试示例
@coerce_args
def test(x: int) -> int:
    return x * 2

# 类型检查器会提示 test 的签名为 (x: Any) -> int
print(test("5"))  # 输出 10,运行时转换为int
print(test(3.14)) # 输出 6,运行时转换为int
# test() 会触发类型检查错误(缺少参数x),符合需求

兼容Python 3.10/3.11的写法(使用typing_extensions)

如果使用Python 3.10或3.11,需要先安装typing_extensions库,再通过类型转换间接实现需求:

from typing_extensions import ParamSpec, TypeVar, Callable, Any
import inspect
from typing import cast

P = ParamSpec("P")
R = TypeVar("R")

def coerce_args(func: Callable[P, R]) -> Callable[P, R]:
    """将函数参数强制转换为其类型提示指定的类型"""
    sig = inspect.signature(func)
    param_types = {
        name: param.annotation
        for name, param in sig.parameters.items()
        if param.annotation is not inspect.Parameter.empty
    }

    def wrapper(*args: Any, **kwargs: Any) -> R:
        bound_args = sig.bind(*args, **kwargs)
        bound_args.apply_defaults()
        
        for name, value in bound_args.arguments.items():
            if name in param_types:
                bound_args.arguments[name] = param_types[name](value)
        
        return func(*bound_args.args, **bound_args.kwargs)
    
    # 告知类型检查器:wrapper保留原参数结构,但允许传入任意类型
    return cast(Callable[P, R], wrapper)

关键说明

  • ParamSpec[P]用于捕获原函数的完整参数结构(包括参数数量、名称、位置/关键字属性)。
  • Python 3.12+的P[Any, ...]语法可以直接将P中所有参数的类型替换为Any,同时严格保留原参数结构。
  • 旧版本通过cast结合Callable[P, R],让类型检查器维持原参数数量要求,同时运行时接受任意类型参数,间接达成需求。

内容的提问来源于stack exchange,提问作者Shane Breeze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 11:44:51