如何将typing.Callable类型提示转换为inspect.Signature函数签名对象?
如何将typing.Callable类型提示转换为inspect.Signature函数签名对象?
场景说明
假设你定义了这样的Callable类型提示:
hint = typing.Callable[[int], float]
要同时用它做类型提示,还要筛选符合该签名的函数,核心是把这个类型提示转成inspect.Signature对象,再和目标函数的签名做对比。
实现方法
要完成转换,关键是提取Callable泛型里的参数类型列表和返回值类型,再用inspect.Signature和inspect.Parameter手动构建签名对象。下面是具体的代码实现:
转换函数
import inspect import typing from typing import Callable, Any def callable_to_signature(callable_hint) -> inspect.Signature: # 校验输入是否为Callable泛型实例 if not (isinstance(callable_hint, typing._GenericAlias) and callable_hint.__origin__ is Callable): raise TypeError("输入必须是typing.Callable的泛型类型提示") args_types, return_type = callable_hint.__args__ # 处理Callable[..., 返回值]的情况(接受任意参数) if args_types is Ellipsis: parameters = [ inspect.Parameter('*args', inspect.Parameter.VAR_POSITIONAL, annotation=Any), inspect.Parameter('**kwargs', inspect.Parameter.VAR_KEYWORD, annotation=Any) ] else: # 生成位置参数,参数名用arg0、arg1...自动命名 parameters = [] for idx, arg_type in enumerate(args_types): param = inspect.Parameter( name=f'arg{idx}', kind=inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=arg_type ) parameters.append(param) # 构建并返回签名对象 return inspect.Signature(parameters=parameters, return_annotation=return_type)
测试示例
用你给出的类型提示测试:
hint = typing.Callable[[int], float] sig = callable_to_signature(hint) print(sig) # 输出: (arg0: int) -> float
签名对比
如果要验证某个函数是否符合该签名,可以提取函数的签名后,对比参数类型和返回值类型:
def func(a: int) -> float: return float(a) # 获取函数的签名 func_sig = inspect.signature(func) # 定义对比逻辑(忽略参数名,只看类型) def signatures_match(sig1: inspect.Signature, sig2: inspect.Signature) -> bool: if len(sig1.parameters) != len(sig2.parameters): return False # 逐个对比参数的注解类型 for p1, p2 in zip(sig1.parameters.values(), sig2.parameters.values()): if p1.annotation != p2.annotation: return False # 对比返回值类型 return sig1.return_annotation == sig2.return_annotation print(signatures_match(sig, func_sig)) # 输出: True
注意事项
- 转换后的参数名是自动生成的
arg0、arg1,和实际函数的参数名可能不同,所以对比时只关注类型注解即可 - 支持处理
Callable[..., float]这种接受任意参数的类型提示 - 如果输入是不带泛型的
typing.Callable,其__args__为(Any, Any),你可以根据需求修改函数逻辑,比如默认处理为任意参数或抛出错误
内容的提问来源于stack exchange,提问作者tierriminator
相关产品推荐
相关产品推荐

