Python中如何在装饰器内获取被装饰函数的默认参数值
解决方法
核心问题是手写的包装函数会覆盖原函数的签名信息,按以下方式修改装饰器即可在函数执行前拿到本次调用真正生效的参数值(包括未传参时自动填充的原函数默认值):
- 用
functools.wraps将原函数的元信息(签名、参数默认值等)拷贝到包装函数上,避免装饰器篡改原函数的属性 - 在包装函数内通过
inspect.signature绑定调用时传入的实参,调用apply_defaults()自动补全未传入参数的默认值,即可直接读取所有生效参数
修正后的完整代码:
import inspect from functools import wraps def check_param(func): @wraps(func) def wrapper(*args, **kwargs): # 基于原函数签名绑定入参,自动填充默认值 func_sig = inspect.signature(func) bound_params = func_sig.bind(*args, **kwargs) bound_params.apply_defaults() # 拿到本次调用实际生效的param值做校验 valid_param = bound_params.arguments['param'] check(valid_param) # 执行原函数逻辑 return func(*args, **kwargs) return wrapper @check_param def func_a(param='a'): print(param) @check_param def func_b(param='b'): print(param)
效果说明
- 无参调用
func_a()时,校验逻辑拿到的valid_param为原函数默认值'a' - 显式传参调用
func_a('custom_val')时,校验逻辑拿到的valid_param为传入的'custom_val' - 该写法兼容任意参数形式的被装饰函数,不需要针对每个函数的参数列表单独调整包装函数逻辑
之前用
inspect无法获取原函数默认值,是因为没有加@wraps(func)装饰包装函数,此时外部读取到的函数签名是包装函数自身的定义,自然无法拿到原函数的默认配置。加上@wraps后,inspect读取到的就是原函数的真实签名,配合参数绑定逻辑就能准确拿到任意调用场景下的实际生效参数。
内容的提问来源于stack exchange,提问作者david
相关产品推荐
相关产品推荐

