functools.wraps 解决了装饰器导致原函数元信息丢失的问题,自动将 name__、__doc__、__module 等关键属性从被装饰函数复制到包装函数,确保调试、帮助系统、ide 和框架正常工作。

functools.wraps 解决了装饰器覆盖原函数元信息的问题。
被装饰函数的 __name__、__doc__ 等属性会丢失
不使用 @wraps 时,装饰器内部通常返回一个新函数(闭包),这个新函数取代了原函数。结果是:
– func.__name__ 变成装饰器里内层函数的名字(比如 'wrapper')
– func.__doc__ 变成内层函数的文档字符串,不是原函数的
– func.__module__、func.__annotations__ 等也可能出错或为空
影响调试、帮助系统和工具链
这些元信息丢失会导致:
– help(func) 显示错误的函数名和说明
– IDE 自动补全或跳转可能指向装饰器内部,而非原始定义位置
– 日志中记录函数名变成 wrapper,难以定位实际逻辑
– 某些依赖函数签名的框架(如 flask 路由、click 命令)可能行为异常
wraps 的作用就是批量复制关键属性
@wraps(func) 是一个装饰器工厂,它会把被装饰函数的以下属性自动拷贝到包装函数上:
– __module__
– __name__
– __qualname__
– __doc__
– __annotations__
– 还有 __dict__ 中的部分内容
本质是调用 functools.update_wrapper(wrapper, wrapped),但更简洁易用。
正确写法示例
对比两种写法:
❌ 不加 wraps:
def my_decorator(f): def wrapper(*args, **kwargs): print("before") result = f(*args, **kwargs) print("after") return result return wrapper @my_decorator def say_hello(): """Print hello""" print("hello")
say_hello.__name__ → 'wrapper',say_hello.__doc__ → None
立即学习“Python免费学习笔记(深入)”;
✅ 加 wraps:
from functools import wraps def my_decorator(f): @wraps(f) # 关键一行 def wrapper(*args, *kwargs): print("before") result = f(args, **kwargs) print("after") return result return wrapper
此时 say_hello.__name__ 仍是 'say_hello',say_hello.__doc__ 正确显示 "Print hello"