全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-19 6 分钟 ✍️ juanwangdev

Python functools.wraps

functools.wraps 用于保留被装饰函数的元信息,避免装饰器覆盖原始函数属性。

问题演示

不使用 wraps 时的问题:

Python
def my_decorator(func):
    def wrapper(*args, **kwargs):
        "这是包装函数的文档"
        return func(*args, **kwargs)
    return wrapper


@my_decorator
def greet(name):
    "向某人问好"
    return f"Hello, {name}!"


print(greet.__name__)    # wrapper(应该是 greet)
print(greet.__doc__)     # 这是包装函数的文档(应该是 向某人问好)

使用 wraps 解决

Python
from functools import wraps


def my_decorator(func):
    @wraps(func)  # 保留被装饰函数的元信息
    def wrapper(*args, **kwargs):
        "这是包装函数的文档"
        return func(*args, **kwargs)
    return wrapper


@my_decorator
def greet(name):
    "向某人问好"
    return f"Hello, {name}!"


print(greet.__name__)    # greet
print(greet.__doc__)     # 向某人问好

wraps 的原理

wraps 实际上是 partial(update_wrapper, ...) 的快捷方式:

Python
from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES

# 查看默认复制的属性
print(WRAPPER_ASSIGNMENTS)
# ('__module__', '__name__', '__qualname__', '__annotations__', '__doc__', '__wrapped__')

print(WRAPPER_UPDATES)
# ('__dict__',)

update_wrapper 函数

Python
from functools import update_wrapper


def my_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)

    # 手动更新属性
    update_wrapper(wrapper, func)
    return wrapper

常用属性保留

Python
from functools import wraps


def debug(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"调用 {func.__name__}")
        print(f"参数: {args}, {kwargs}")
        print(f"模块: {func.__module__}")
        return func(*args, **kwargs)
    return wrapper


@debug
def calculate(a: int, b: int) -> int:
    "计算两数之和"
    return a + b


print(calculate.__name__)        # calculate
print(calculate.__doc__)         # 计算两数之和
print(calculate.__annotations__) # {'a': int, 'b': int, 'return': int}
print(calculate.__wrapped__)     # 原始函数对象

wrapped 的妙用

使用 wraps 后,可以通过 __wrapped__ 访问原始函数:

Python
from functools import wraps


def strong_auth(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("权限验证...")
        return func(*args, **kwargs)
    return wrapper


@strong_auth
def delete_user(user_id):
    "删除用户"
    return f"已删除用户 {user_id}"


# 通过 __wrapped__ 调用原始函数(跳过装饰器)
delete_user.__wrapped__(1)  # 直接调用,跳过权限验证

自定义保留属性

可以指定要保留的属性:

Python
from functools import wraps


def custom_decorator(func):
    @wraps(func, assigned=('__name__', '__doc__'), updated=())
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

在类装饰器中使用

类装饰器同样需要保留元信息:

Python
from functools import wraps


class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
        wraps(func)(self)  # 关键:保留元信息

    def __call__(self, *args, **kwargs):
        self.count += 1
        return self.func(*args, **kwargs)


@CountCalls
def process(data):
    "处理数据"
    return data * 2


print(process.__name__)  # process
print(process.__doc__)  # 处理数据

常用装饰器模板

Python
from functools import wraps


# 无参数装饰器
def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # 前置逻辑
        result = func(*args, **kwargs)
        # 后置逻辑
        return result
    return wrapper


# 带参数装饰器
def decorator_with_args(arg1, arg2=None):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 使用 arg1, arg2
            return func(*args, **kwargs)
        return wrapper
    return decorator

要点总结

属性说明
__name__函数名称
__doc__文档字符串
__module__所在模块
__annotations__类型注解
__wrapped__原始函数引用
要点说明
位置必须放在 wrapper 函数定义前
作用复制函数元信息到包装函数
类装饰器使用 wraps(func)(self)
访问原函数通过 __wrapped__ 属性

使用 @wraps(func) 是编写规范装饰器的最佳实践,确保调试信息和文档正确显示。

D:\git2\jwdev\articles\PYTHON\进阶\装饰器深入\functools.wraps.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python 状态保持装饰器
下一篇 → Python 带参数装饰器
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库