使用inspect.Parameter与Signature API强制Python函数遵循指定签名
手动构造指定inspect签名并实现函数合规校验
完全可以不使用Signature.from_callable方法,从零手动构造出目标签名对象,再基于该对象做严格的函数签名合规校验。
手动构造目标签名
inspect模块本身提供了Parameter和Signature两个基础类,用来描述函数参数和完整签名,只需要按照目标规则逐个定义参数、指定返回值注解即可拼装出和示例完全一致的签名对象:
import inspect import torch from torch import nn from inspect import Parameter, Signature # 按顺序定义两个入参,参数类型为POSITIONAL_OR_KEYWORD即支持位置传参也支持关键字传参,无默认值 param_list = [ Parameter( name="patch", kind=Parameter.POSITIONAL_OR_KEYWORD, annotation=torch.Tensor ), Parameter( name="model", kind=Parameter.POSITIONAL_OR_KEYWORD, annotation=nn.Module ) ] # 组装签名,指定返回值类型注解 target_sig = Signature( parameters=param_list, return_annotation=torch.Tensor )
直接打印target_sig就能得到和from_callable生成结果完全一致的输出:
<Signature (patch: torch.Tensor, model: torch.nn.modules.module.Module) -> torch.Tensor>
严格校验函数是否符合签名规范
直接对比传入函数的签名和手动构造的目标签名是否相等,就能完成基础校验;如果需要抛出明确的错误提示,可以逐字段校验参数名、参数类型、参数注解、返回值注解:
def check_predictor(func) -> bool: # 先判断传入对象是否可被提取签名 if not callable(func): raise TypeError("传入对象不是可调用对象") try: func_sig = inspect.signature(func) except ValueError: raise TypeError("传入可调用对象无法提取有效签名") # 签名完全匹配直接返回校验通过 if func_sig == target_sig: return True # 逐字段校验抛出明确错误 # 校验返回值注解 if func_sig.return_annotation != target_sig.return_annotation: raise TypeError( f"返回值注解不匹配,期望{target_sig.return_annotation},实际{func_sig.return_annotation}" ) target_params = list(target_sig.parameters.values()) func_params = list(func_sig.parameters.values()) # 校验参数数量 if len(func_params) != len(target_params): raise TypeError( f"参数数量不匹配,期望{len(target_params)}个参数,实际{len(func_params)}个" ) # 逐参数校验名称、传参类型、注解 for expect_param, actual_param in zip(target_params, func_params): if expect_param.name != actual_param.name: raise TypeError(f"参数名不匹配,期望位置{list(target_sig.parameters.keys()).index(expect_param.name)+1}的参数名为{expect_param.name},实际为{actual_param.name}") if expect_param.kind != actual_param.kind: raise TypeError(f"参数{expect_param.name}的传参规则不匹配,期望为{expect_param.kind}类型,实际为{actual_param.kind}类型") if expect_param.annotation != actual_param.annotation: raise TypeError(f"参数{expect_param.name}的类型注解不匹配,期望为{expect_param.annotation},实际为{actual_param.annotation}") return True
注:上述校验是静态签名层面的严格匹配,不会校验函数运行时实际传入、返回的数据类型,如果需要运行时类型拦截,可以搭配类型检查工具在函数调用时做校验。
内容的提问来源于stack exchange,提问作者Yere
相关产品推荐
相关产品推荐

