Python __wrapped__介绍(函数属性,用于指向被装饰前的原始函数)functools.wraps、函数签名检查inspect模块、多层装饰器链
·
文章目录
深入理解 Python 的 __wrapped__ 属性
在 Python 的装饰器(decorator)体系中,函数包装(wrapping)是一种非常常见的技术。然而,函数一旦被装饰,原始函数的元信息(如名称、文档字符串、签名等)往往会被覆盖。为了解决这个问题,Python 引入了一个非常关键但容易被忽视的属性:__wrapped__。
本文将系统介绍 __wrapped__ 的作用、原理以及实际应用场景。
一、什么是 __wrapped__?
__wrapped__ 是一个函数属性,用于指向被装饰前的原始函数。
简单来说:
wrapped_function.__wrapped__ == original_function
这个属性通常由标准库中的 functools.wraps 自动设置。
二、为什么需要 __wrapped__?
考虑一个最简单的装饰器:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before call")
return func(*args, **kwargs)
return wrapper
使用它:
@my_decorator
def add(a, b):
return a + b
此时:
print(add.__name__) # 输出: wrapper
问题出现了:原函数 add 的信息丢失了。
三、functools.wraps 的作用
为了解决这个问题,我们通常这样写:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before call")
return func(*args, **kwargs)
return wrapper
@wraps(func) 做了几件关键的事情:
- 复制元信息(如
__name__,__doc__) - 设置
__wrapped__属性
等价于:
wrapper.__wrapped__ = func
四、__wrapped__ 的核心用途
1. 访问原始函数
print(add.__wrapped__) # <function add at ...>
甚至可以直接调用原始函数:
result = add.__wrapped__(2, 3)
print(result) # 5(跳过装饰器)
2. 支持函数签名检查(inspect)
Python 的 inspect 模块会使用 __wrapped__ 来获取真实函数签名:
import inspect
print(inspect.signature(add))
如果没有 __wrapped__,签名会变成:
(*args, **kwargs)
而不是:
(a, b)
3. 多层装饰器链
当有多个装饰器时:
@decorator1
@decorator2
def func():
pass
会形成链式结构:
func -> wrapper1 -> wrapper2 -> original
可以通过不断访问:
func.__wrapped__.__wrapped__
逐层回溯到最初的函数。
4. 调试和工具支持
很多工具(如:
- 调试器
- 文档生成工具
- 类型检查工具
)都会依赖 __wrapped__ 来“还原”真实函数。
五、实现原理简析
functools.wraps 本质上是一个装饰器工厂:
def wraps(wrapped):
def decorator(wrapper):
wrapper.__wrapped__ = wrapped
return wrapper
return decorator
实际实现中还会复制:
__module____name____qualname____doc____annotations__
六、最佳实践
✅ 总是使用 functools.wraps
from functools import wraps
这是推荐的标准写法,否则:
- 调试困难
- introspection 失效
- 工具链支持变差
❗ 不要手动忽略 __wrapped__
如果你写自定义装饰器但不设置 __wrapped__,可能导致:
inspect失效- FastAPI / Click 等框架行为异常
七、总结
__wrapped__ 虽然是一个小属性,但在 Python 生态中扮演着关键角色:
- 保留函数原始引用
- 支持 introspection(自省)
- 让工具链正常工作
- 提升调试体验
一句话总结:
__wrapped__是装饰器世界中的“回溯指针”。
更多推荐


所有评论(0)