如何获取被装饰器包装后的原函数的参数名称?
获取被装饰函数的参数名称
当你用装饰器包装函数后,直接访问query_data其实拿到的是装饰器返回的包装器函数start_end_date_wrapper_args,所以query_data.__code__.co_varnames返回的是包装器的参数kwargs。要获取原函数query_data的参数,核心是先拿到被包装的原函数对象,下面提供两种可行方法:
方法一:手动给包装器添加原函数引用
修改你的装饰器,给包装器函数添加一个指向原函数的属性(比如标准约定的__wrapped__):
import datetime as dt def start_end_date_wrapper_fn(function): def start_end_date_wrapper_args(**kwargs): kwargs = kwargs.copy() # 仅在函数作用域内更新 if kwargs.get('forecast_or_train') == 'forecast': kwargs['start_date'] = kwargs['start_date'] + dt.timedelta(days=-30) kwargs['end_date'] = kwargs['end_date'] + dt.timedelta(days=30) del kwargs['forecast_or_train'] # 修正原代码中的笔误(原写为train_or_forecast) return function(**kwargs) # 手动绑定原函数到包装器的__wrapped__属性 start_end_date_wrapper_args.__wrapped__ = function return start_end_date_wrapper_args @start_end_date_wrapper_fn def query_data(start_date, end_date): # do something pass
之后就可以通过__wrapped__获取原函数,再提取参数:
# 方法1:用inspect模块(推荐,兼容复杂参数场景) import inspect original_func = query_data.__wrapped__ params = inspect.signature(original_func).parameters.keys() print(list(params)) # 输出: ['start_date', 'end_date'] # 方法2:用__code__属性(仅适用于简单位置参数) original_code = query_data.__wrapped__.__code__ print(original_code.co_varnames[:original_code.co_argcount]) # 输出: ('start_date', 'end_date')
方法二:使用functools.wraps(推荐标准做法)
Python标准库的functools.wraps专门用于保留被装饰函数的元数据,它会自动给包装器添加__wrapped__属性,同时同步原函数的__name__、__doc__等信息:
import datetime as dt import functools def start_end_date_wrapper_fn(function): @functools.wraps(function) # 添加这一行即可 def start_end_date_wrapper_args(**kwargs): kwargs = kwargs.copy() if kwargs.get('forecast_or_train') == 'forecast': kwargs['start_date'] = kwargs['start_date'] + dt.timedelta(days=-30) kwargs['end_date'] = kwargs['end_date'] + dt.timedelta(days=30) del kwargs['forecast_or_train'] return function(**kwargs) return start_end_date_wrapper_args @start_end_date_wrapper_fn def query_data(start_date, end_date): # do something pass
获取参数的方式和方法一完全一致:
import inspect sig = inspect.signature(query_data.__wrapped__) print(list(sig.parameters.keys())) # ['start_date', 'end_date']
补充说明
inspect.signature是更可靠的参数获取方式,能处理默认参数、可变参数(*args、**kwargs)等复杂场景;__code__.co_varnames会包含函数内部的局部变量,所以需要配合co_argcount截取前N个元素才能得到位置参数。
内容的提问来源于stack exchange,提问作者Iain MacCormick
相关产品推荐
相关产品推荐

