You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让类装饰器适配实例方法并支持额外属性与__self__利用?

类装饰器适配实例方法的问题与解决方案

问题背景

现有如下类装饰器实现:

class Foo:
    def __init__(self, func):
        self.func = func
        self.variable1 = 1
        self.variable2 = 2
    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

该装饰器直接用于实例方法时会报错:

class Bar:
    @Foo
    def dance(self):
        return 0
Bar().dance()  # TypeError: missing 1 required positional argument: 'self'

问题1:能否让dance()表现得像内置绑定方法,同时允许访问Bar().dance.variable1这类额外变量?

可以实现,核心是让Foo类遵循描述符协议,通过实现__get__方法处理实例属性的绑定逻辑,同时保留对装饰器实例属性的访问能力。

修改后的Foo类代码:

class Foo:
    def __init__(self, func):
        self.func = func
        self.variable1 = 1
        self.variable2 = 2

    def __get__(self, instance, owner):
        # 类层面访问(如Bar.dance)时返回装饰器自身
        if instance is None:
            return self
        # 创建绑定方法包装类,模拟内置绑定行为
        class BoundMethod:
            def __call__(self, *args, **kwargs):
                # 自动传入实例作为第一个参数,模拟绑定方法
                return self.func(instance, *args, **kwargs)
            
            # 代理属性访问到原装饰器实例
            def __getattr__(self, name):
                return getattr(self.__foo_instance, name)
        
        bound = BoundMethod()
        bound.func = self.func
        bound.__foo_instance = self
        bound.__self__ = instance  # 模拟内置绑定方法的__self__属性
        return bound

    def __call__(self, *args, **kwargs):
        # 类层面直接调用装饰器时执行(如Foo(func)())
        return self.func(*args, **kwargs)

测试验证:

class Bar:
    @Foo
    def dance(self):
        return 0

b = Bar()
print(b.dance())          # 输出:0(正常调用,自动传入self)
print(b.dance.variable1)  # 输出:1(访问装饰器的额外变量)
print(b.dance.__self__)   # 输出:<__main__.Bar object at 0x...>(模拟内置绑定方法的__self__)

问题2:未装饰的Bar().dance拥有指向Bar对象的__self__属性,能否在variable1中利用该属性?

可以,但不能在Foo的__init__阶段直接使用(因为装饰器在类定义时初始化,此时还没有Bar实例),需要将variable1设计为动态属性,在绑定方法被访问时再获取__self__(即Bar实例)。

修改后的Foo类代码(以动态生成variable1为例):

class Foo:
    def __init__(self, func):
        self.func = func
        self.variable2 = 2

    def __get__(self, instance, owner):
        if instance is None:
            return self
        
        class BoundMethod:
            def __call__(self, *args, **kwargs):
                return self.func(instance, *args, **kwargs)
            
            # 将variable1设为动态属性,利用绑定的实例(__self__)
            @property
            def variable1(self):
                return f"绑定实例ID:{id(instance)},实例属性:{instance.__dict__}"
            
            # 代理其他属性到原装饰器实例
            def __getattr__(self, name):
                return getattr(self.__foo_instance, name)
        
        bound = BoundMethod()
        bound.func = self.func
        bound.__foo_instance = self
        bound.__self__ = instance
        return bound

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

测试验证:

class Bar:
    def __init__(self, name):
        self.name = name
    
    @Foo
    def dance(self):
        return 0

b1 = Bar("Alice")
print(b1.dance.variable1)  # 输出:绑定实例ID:xxx,实例属性:{'name': 'Alice'}
b2 = Bar("Bob")
print(b2.dance.variable1)  # 输出:绑定实例ID:yyy,实例属性:{'name': 'Bob'}

内容的提问来源于stack exchange,提问作者feiyang472

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 00:42:35