Python|functools.wraps 装饰器元信息
一、没有 @wraps 时发生了什么?
def log_decorator(func): # 此时 func = 原始的 test 函数
def inner(*args, **kwargs):
print("执行前")
return func(*args, **kwargs)
return inner # 返回 inner 函数
@log_decorator
def test(): # 这行代码执行完毕后,test 被重新赋值了!
"""这是test函数文档"""
pass
# @log_decorator 等价于执行:
# test = log_decorator(test) # ← test 不再指向原函数,而是指向 inner
关键理解:
- 当你写
@log_decorator时,Python 会立即执行test = log_decorator(test) log_decorator返回的是inner函数- 所以
test这个名字被重新绑定到了inner上 - 原始的 test 函数已经丢失了! (没有任何变量指向它)
这就是为什么打印 test.name 会输出 inner——因为 test 现在就是 inner,是那个内部包装函数的名字。
二、@wraps 做了什么?
import functools
def log_decorator(func):
@functools.wraps(func) # 这行是关键!
def inner(*args, **kwargs):
print("执行前")
return func(*args, **kwargs)
return inner
@functools.wraps(func) 等价于执行:
def inner(*args, **kwargs):
print("执行前")
return func(*args, **kwargs)
# wraps 做的事:
inner.__name__ = func.__name__ # 把原函数的名字复制过来
inner.__doc__ = func.__doc__ # 把原函数的文档复制过来
inner.__module__ = func.__module__ # 把原函数的模块复制过来
# ... 还复制了很多其他元信息
关键理解:
@wraps没有恢复原始函数,test仍然指向inner,不是原始函数@wraps只是把原函数的元信息(名字、文档、注解等)复制到 inner 上- 所以
test.__name__显示的是被复制过来的值,变成了'test'
三、图解整个过程
没有 @wraps 时:
原始函数: test → function (name='test', doc='这是test函数文档')
↓
@log_decorator 执行
↓
test = log_decorator(test)
↓
现在: test → inner (name='inner', doc=None) ← 原始的 test 函数丢失了
有 @wraps 时:
原始函数: test → function (name='test', doc='这是test函数文档')
↓
@log_decorator 执行
↓
test = log_decorator(test)
↓
@wraps 把元信息复制过来
↓
现在: test → inner (name='test', doc='这是test函数文档') ← 复制了元信息
四、为什么 @wraps 很重要?
没有 @wraps 会导致各种问题:
- 调试困难:报错时显示
inner而不是test,找不到问题来源 - 文档丢失:
help(test)显示的是inner的文档(通常是空的) - 框架功能失效:一些框架(如 Flask、FastAPI)依赖函数名来做路由映射
- 装饰器嵌套时层层丢失:函数名变成
inner1、inner2、inner3……无法追踪

浙公网安备 33010602011771号