Python函数多次装饰后帮助信息丢失,是因为装饰器用新函数替换原函数导致元数据被覆盖;解决方法是每层装饰器内部包装函数均使用@functools.wraps(func)自动复制__name__、__doc__等属性。

Python 中函数被多次装饰后帮助信息丢失,是因为装饰器通常会用新函数替换原函数,导致 help()、docstring、函数名等元数据被覆盖。解决方法是让装饰器**保留原始函数的元数据**,核心是使用 functools.wraps。
用 @functools.wraps 保留元数据
这是最标准、最推荐的做法。每次写装饰器时,在内层包装函数上加上 @wraps(func),它会自动复制 __name__、__doc__、__module__、__annotations__ 等关键属性。
示例:
from functools import wrapsdef log_calls(func): @wraps(func) # ← 关键:保留原函数元数据 def wrapper(*args, *kwargs): print(f"Calling {func.name}") return func(args, **kwargs) return wrapper
def add_one(func): @wraps(func) def wrapper(*args, *kwargs): result = func(args, **kwargs) return result + 1 return wrapper
@log_calls @add_one def square(x): """Return the square of x.""" return x * x
此时 help(square) 正确显示:Help on function square in module __main__:square(x) Return the square of x.
立即学习“Python免费学习笔记(深入)”;
多层装饰时,每层都要用 @wraps
如果装饰器嵌套三层(比如 @A → @B → @C → 函数),那么 A、B、C 三个装饰器内部的包装函数都必须各自调用 @wraps。漏掉任意一层,元数据就会在那一层中断。
- 装饰器本身不加
@wraps→ 元数据丢失 - 只在最外层加,中间层没加 → 中间层已覆盖,外层补救无效
- 每一层都加 → 原始函数的
__doc__和名字能穿透所有层级
检查是否生效的小技巧
调试时可快速验证:
-
print(square.__name__)→ 应输出'square',不是'wrapper' -
print(square.__doc__)→ 应输出"Return the square of x." -
help(square)→ 显示内容应和原始函数一致
不推荐的手动复制(仅作了解)
理论上可以手动赋值:
def bad_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
wrapper.__module__ = func.__module__
return wrapper
但容易遗漏属性(如 __annotations__、__dict__),且不可靠。务必优先使用 @functools.wraps。










