Python:使用functiontools.wraps来实现装饰器。
已于 2026年01月12日 14:02 修改
访问次数:0
你这里的 warps 实际上是 wraps(functools.wraps),我下面按官方 API + 实战角度完整给你讲清楚。
一、wraps 是什么?
functools.wraps(wrapped,
assigned=WRAPPER_ASSIGNMENTS,
updated=WRAPPER_UPDATES)
📌 wraps 是一个“装饰器的装饰器”
- 用来装饰 wrapper 函数
- 目的是:复制被装饰函数(wrapped)的元数据到 wrapper 上
二、wraps 的完整 API
函数签名
functools.wraps(
wrapped,
assigned=('__module__', '__name__', '__qualname__', '__doc__', '__annotations__'),
updated=('__dict__',)
)
三、参数详解(非常重要)
1️⃣ wrapped(必填)
wrapped: Callable
- 被装饰的原函数
- wraps 会把它的属性复制到 wrapper
@wraps(original_func)
def wrapper(...):
...
2️⃣ assigned(可选)
assigned: tuple[str]
📌 直接赋值复制的属性名
默认值:
('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')
含义说明:
| 属性 | 作用 |
|---|---|
__name__ | 函数名 |
__qualname__ | 完整限定名 |
__doc__ | 文档字符串 |
__module__ | 所属模块 |
__annotations__ | 类型注解 |
📌 示例:只复制 name 和 doc
@wraps(func, assigned=("__name__", "__doc__"))
def wrapper():
...
3️⃣ updated(可选)
updated: tuple[str]
📌 用于 update(合并)的属性
默认值:
('__dict__',)
__dict__ 是什么?
- 存储函数的自定义属性
def f(): pass
f.version = "1.0"
行为区别:
| 属性 | 复制方式 |
|---|---|
| assigned | 覆盖赋值 |
| updated | 调用 .update() 合并 |
四、wraps 的返回值
wraps(...) -> Callable
⚠️ wraps 返回的是一个装饰器函数
decorator = wraps(func)
decorator(wrapper) -> wrapper
等价于:
wrapper = update_wrapper(wrapper, func)
五、wraps 与 update_wrapper 的关系
实际源码关系
def wraps(wrapped, assigned=..., updated=...):
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
👉 wraps 是 update_wrapper 的语法糖
update_wrapper(底层函数)
functools.update_wrapper(
wrapper,
wrapped,
assigned=WRAPPER_ASSIGNMENTS,
updated=WRAPPER_UPDATES
)
📌 如果你需要动态包装,直接用它
六、wraps 做了哪些“隐藏操作”?
除了复制属性,还会设置:
wrapper.__wrapped__ = wrapped
这个属性的作用:
- 支持 inspect.unwrap
- 支持多层装饰器拆解
- 框架反射、调试工具依赖
七、完整示例(带所有参数)
from functools import wraps
def decorator(func):
@wraps(
func,
assigned=("__name__", "__doc__", "__annotations__"),
updated=("__dict__",)
)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
八、什么时候需要自定义 assigned / updated?
场景 1:避免覆盖 wrapper 自己的 doc
@wraps(func, assigned=("__name__",))
场景 2:多层代理函数
@wraps(func, updated=())
九、常见误区
❌ @wraps 装饰原函数
✔ 装饰 wrapper
❌ @wraps() 不传 wrapped
✔ 必须传原函数
十、测试代码
from functools import wraps
def test_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
def test_decorator_1(func):
def wrapper(*args, **kwargs):
print("Start")
result = func(*args, **kwargs)
print("End")
return result
return wrapper
@test_decorator
def function1(n):
return n * n
@test_decorator_1
def function2(n):
return n + n
if __name__ == "__main__":
print(function1.__name__)
print(function1.__qualname__)
print(function1.__doc__)
print(function1.__module__)
print(function1.__annotations__)
print("-----")
print(function2.__name__)
print(function2.__qualname__)
print(function2.__doc__)
print(function2.__module__)
print(function2.__annotations__)
十一、面试级总结
functools.wraps 是用于装饰装饰器内部 wrapper 函数的工具,通过复制被装饰函数的元数据并设置 __wrapped__,保证函数身份、调试、反射和框架行为的正确性。
评论(0)