首页 新闻 会员 周边 捐助

self.__wrapped__作用?

0
[已解决问题] 解决于 2025-08-14 17:50

self.wrapped = func # 关键2:显式保存原函数
这是什么?内置函数__wrapped __没见过,和装饰器wraps()有什么关系,我记得有from functools import wraps可以保留原函数的元数据信息

流程:
2. 类装饰器的完整生命周期
阶段一:装饰阶段(创建实例)

python
class Decorator:
    def __init__(self, func):
        self.func = func  # 保存原函数
        self.call_count = 0

@Decorator  # 等价于 my_func = Decorator(my_func)
def my_func(): pass
Python 遇到 @Decorator 时,会立即创建 Decorator 类的实例

将 my_func 作为参数传给 init

实例化后的对象替换原函数名(my_func 现在指向装饰器实例)

阶段二:调用阶段(实例伪装成函数)

my_func()  # 实际调用的是实例的 __call__ 方法
当调用 my_func() 时,因为 my_func 已经是实例对象

Python 自动调用 实例.__call__() 方法

call 中执行装饰逻辑并调用原函数

_java_python的主页 _java_python | 小虾三级 | 园豆:1050
提问于:2025-08-14 15:41
< >
分享
最佳答案
0

wrapped 用于保存原始函数引用,wrapped 默认只在使用 functools.wraps 时才会被自动设置。如果自己手写装饰器而没用 wraps,那么被包装函数上就不会有 wrapped 这个属性。
wraps() 函数内部会自动创建 wrapped 属性

@wraps(original_func)
def decorated_func(*args, **kwargs):
    pass

# 等价于:
decorated_func.__wrapped__ = original_func

类装饰器示例中:

class DecoratorClass():
    def __init__(self, func):
        wraps(func)(self)       # 1. 用wraps复制元信息
        self.__wrapped__ = func # 2. 显式保存原函数(双保险)

双重保障机制:

wraps(func)(self)

将 func 的元信息(name、__doc__等)复制给实例

隐式 设置 self.wrapped = func(自动设置了,所以下面的self.wrapped = func不用设置
)
···多余
self.wrapped = func

显式 存储原函数引用

确保即使 wraps 行为变化也能正常工作
···

····
wraps(func)

返回一个 装饰器工厂函数,这个工厂函数"记住"了原函数 func

(self)

将类实例 self 作为参数传递给上一步生成的装饰器

相当于执行:

python
decorator = wraps(func) # 创建装饰器
decorator(self) # 装饰实例
······

和下面

假设没有 wraps,手动实现相同功能:

python
def manual_wraps(original_func):
    def decorator(target):
        # 复制元数据
        target.__name__ = original_func.__name__
        target.__doc__ = original_func.__doc__
        target.__module__ = original_func.__module__
        target.__annotations__ = original_func.__annotations__
        # ...其他属性
        return target
    return decorator

class Decorator:
    def __init__(self, func):
        manual_wraps(func)(self)  # 手动实现的效果
        self.__wrapped__ = func
wraps() 本质上就是自动完成这些属性复制的标准化工具

等价

所以:

三、实际作用演示
没有 wraps 的情况:
python
def bad_decorator(func):
    class Wrapper:
        def __call__(self, *args, **kwargs):
            return func(*args, **kwargs)
    return Wrapper()

@bad_decorator
def example(): pass

print(example.__name__)  # 输出:'Wrapper' (丢失原函数名)
使用 wraps 的情况:
python
from functools import wraps

def good_decorator(func):
    @wraps(func)
    class Wrapper:
        def __call__(self, *args, **kwargs):
            return func(*args, **kwargs)
    return Wrapper()

@good_decorator
def example(): pass

print(example.__name__)  # 输出:'example' (保留元信息)

当 wraps(func)(self) 用于类装饰器时:

元数据转移路径:

text
原函数(func) → 通过wraps → 类实例(self) 可以print(type(原始函数))看出已经class类型来(obj),如果是type(类)是type类型
为什么要装饰实例:
因为类装饰器最终返回的是实例对象,需要让这个实例"伪装"成原函数,self 指代装饰器类的实例对象
等价于:
def my_func(): pass
my_func = DecoratorClass(my_func) # 创建实例,self就是该实例

文档字符串(Docstring):位于模块、函数、类或方法定义开头的字符串,用于描述其用途

__doc__ 属性:Python 自动将这些文档字符串存储在这个特殊属性中

如何添加 __doc__
1. 函数/方法中添加
python
def calculate_sum(a, b):
    """计算两个数字的和
    
    参数:
        a (int/float): 第一个数字
        b (int/float): 第二个数字
    
    返回:
        int/float: 两个数字的和
    """
    return a + b

print(calculate_sum.__doc__)
查看文档的多种方式
内置 help() 函数

python
help(sorted)
直接访问 __doc__

python
print(list.__doc__)
_java_python | 小虾三级 |园豆:1050 | 2025-08-14 17:46
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册