Python 2.7中包装函数后如何保留原函数的参数名?
在Python 2.7中让装饰后的函数保留原参数名
问题根源
__code__是Python函数对象的只读属性,functools.wraps仅能复制函数的元数据(如__name__、__doc__),无法修改或替换包装函数(wrapper)的__code__。因此直接访问f.__code__.co_varnames得到的是wrapper自身的('args', 'kwargs'),而非原函数的参数名。
可行解决方案
方案1:递归获取最内层原函数
利用functools.wraps给包装函数添加的__wrapped__属性,递归找到最原始的函数,再访问其__code__.co_varnames:
from functools import wraps def get_original_func(func): # 递归遍历__wrapped__属性,直到找到最内层原函数 while hasattr(func, '__wrapped__'): func = func.__wrapped__ return func def deco(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @deco def f(a): pass original_func = get_original_func(f) print original_func.__code__.co_varnames # 输出 ('a',)
方案2:给包装函数添加自定义属性
在装饰器中直接将原函数的参数名存储为包装函数的自定义属性,后续直接访问该属性即可:
from functools import wraps def deco(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) # 给包装函数添加自定义属性,存储原函数的参数名 wrapper.__original_co_varnames__ = func.__code__.co_varnames return wrapper @deco def f(a): pass print f.__original_co_varnames__ # 输出 ('a',)
方案3:结合inspect模块获取参数
通过inspect模块的工具函数,配合递归获取原函数,直接提取参数列表:
import inspect from functools import wraps def get_original_func(func): while hasattr(func, '__wrapped__'): func = func.__wrapped__ return func def deco(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @deco def f(a): pass original_func = get_original_func(f) argspec = inspect.getargspec(original_func) print tuple(argspec.args) # 输出 ('a',)
说明
functools.wraps本身没有提供修改参数名相关属性的能力,因为__code__属性的只读特性无法绕过。上述方案都是通过间接方式获取原函数的参数信息,而非修改包装函数的__code__。
内容的提问来源于stack exchange,提问作者user20731429
相关产品推荐
相关产品推荐

