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
在整本书中我们所涉及许多的Flex框架源码,但为了简洁,我们不总是显示所指的代码。当你阅读这本书时,要求你打开Flex Builder,或能够访问Flex3框架的源码,跟随着我们所讨论源码是怎么工作及为什么这样做。 如果你跟着阅读源码,请注意,我们经常跳过功能或者具体的代码,以便我们可以对应当前的主题。这样能防止我们远离当前的主题,主要是讲解代码的微妙之处。这并不是说那些代码的作用不重要,而是那些代码处理特别的案例,防止潜在的错误或在生命周期的后面来处理,只是我们当前没有讨论它。有需要的朋友可以下载看看
立即学习“Python免费学习笔记(深入)”;
✅ 加 wraps:
from functools import wrapsdef 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"









