配置所需参数后装饰器仍无法识别位置参数的问题排查
问题根源与修复方案
你的装饰器触发TypeError的核心原因:sig.bind(*args, **kwargs)会严格校验原函数的签名——原函数里b是无默认值的必填参数(位于/和*args之间,属于POSITIONAL_OR_KEYWORD类型),调用foo(10, d=22)时缺少b,bind会直接抛出错误,根本走不到后续注入默认值的逻辑。
修复后的完整代码
from functools import wraps from inspect import signature def default_args(defaults): def decorator(func): sig = signature(func) # 禁止给仅限位置参数设置默认值 for param in sig.parameters.values(): if param.kind == param.POSITIONAL_ONLY and param.name in defaults: raise ValueError(f"Parameter {param.name} of function {func.__name__} is positional only and cannot be set by default") @wraps(func) def wrapper(*args, **kwargs): # 用bind_partial替代bind,允许部分参数绑定,避免必填参数缺失直接报错 bound = sig.bind_partial(*args, **kwargs) # 注入自定义默认值 for name, val in defaults.items(): if name not in bound.arguments: bound.arguments[name] = val # 应用原函数自带的默认值(如果未被自定义覆盖) bound.apply_defaults() return func(*bound.args, **bound.kwargs) # 更新包装函数的签名,展示正确的默认值 wrapper.__signature__ = sig.replace( parameters=[ p.replace(default=defaults.get(p.name, p.default)) for p in sig.parameters.values() ] ) return wrapper return decorator @default_args({'b': 15, 'd': 17, 'c': 8}) def foo(a, /, b, *args, c=5, d, **kwargs): """My Function""" print(f"{a=} {b=} {args=} {c=} {d=} {kwargs=}") # 测试 foo(10, d=22) # 输出: a=10 b=15 args=() c=8 d=22 kwargs={} foo(10, 20, d=11) # 输出: a=10 b=20 args=() c=8 d=11 kwargs={}
关键修改说明
- 替换
bind为bind_partial:bind_partial不强制要求所有必填参数都存在,给我们留了注入默认值的空间。 - 添加
bound.apply_defaults():确保原函数自带的默认值(比如c原本的5)在未被自定义覆盖时能正常生效。 - 修正函数名引用:原代码里的
func.name是错误的,应该用func.__name__来获取函数名。
内容的提问来源于stack exchange,提问作者Rewaster
相关产品推荐
相关产品推荐

