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

Python 如何让一个函数在被装饰多次后还能正确显示帮助信息  第1张

Python 中函数被多次装饰后帮助信息丢失,是因为装饰器通常会用新函数替换原函数,导致 help()docstring、函数名等元数据被覆盖。解决方法是让装饰器**保留原始函数的元数据**,核心是使用 functools.wraps

@functools.wraps 保留元数据

这是最标准、最推荐的做法。每次写装饰器时,在内层包装函数上加上 @wraps(func),它会自动复制 __name____doc____module____annotations__ 等关键属性。

示例:

from functools import wraps

def 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