装饰函数时如何保持str(func)与repr(func)输出与原函数一致?
解决装饰器导致函数str/repr与原函数不一致的问题
这个问题在Python装饰器使用中太常见了——当你用装饰器包装函数后,默认情况下包装函数(wrapper)会完全掩盖原函数的元数据,包括__name__、__doc__,以及str()/repr()的输出结果,导致打印出来的是类似<function decorator.<locals>.wrapper at 0x10323e048>的信息,完全看不出原函数的样子。
最推荐的方案:使用functools.wraps
Python标准库的functools.wraps就是专门为解决这个问题设计的,它是一个装饰器,能把原函数的所有元数据(包括名称、文档字符串、模块信息、注解等)复制到包装函数上,让包装函数在外观上和原函数完全一致。
示例代码:
先看不加wraps的错误情况:
def decorator(func): def wrapper(*args, **kwargs): print("执行前的操作") result = func(*args, **kwargs) print("执行后的操作") return result return wrapper @decorator def my_func(): """这是我的测试函数""" pass print(str(my_func)) # 输出: <function decorator.<locals>.wrapper at 0x...> print(repr(my_func)) # 同样输出包装器的信息
加上functools.wraps后的正确写法:
import functools def decorator(func): # 用wraps装饰wrapper,传入原函数func @functools.wraps(func) def wrapper(*args, **kwargs): print("执行前的操作") result = func(*args, **kwargs) print("执行后的操作") return result return wrapper @decorator def my_func(): """这是我的测试函数""" pass print(str(my_func)) # 输出: <function my_func at 0x...> print(repr(my_func)) # 输出: <function my_func at 0x...> # 同时原函数的其他元数据也保留了 print(my_func.__name__) # 输出: my_func print(my_func.__doc__) # 输出: 这是我的测试函数
手动设置元数据(不推荐,仅作了解)
如果你不想依赖functools,也可以手动复制原函数的元数据,甚至自定义__repr__方法:
def decorator(func): def wrapper(*args, **kwargs): print("执行前的操作") result = func(*args, **kwargs) print("执行后的操作") return result # 手动复制关键元数据 wrapper.__name__ = func.__name__ wrapper.__doc__ = func.__doc__ wrapper.__module__ = func.__module__ # 自定义repr,让它返回原函数的repr wrapper.__repr__ = lambda f=func: repr(f) return wrapper
不过这种方式需要手动处理所有需要的元数据,容易遗漏__annotations__、__qualname__这类细节,所以还是优先用functools.wraps更稳妥。
内容的提问来源于stack exchange,提问作者Hameer Abbasi
相关产品推荐
相关产品推荐

