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

Python装饰类方法时,如何访问被装饰方法的self?

如何访问被装饰类方法的self?

当使用类实现的装饰器修饰类的实例方法时,会出现装饰器内的self指向装饰器实例而非被装饰类(如示例中的A)实例的问题,导致无法访问类实例的属性,同时参数传递也存在错误。

示例错误代码:

class Decorator:
    def __init__(self, func):
        self.func = func

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


class A:
    def __init__(self):
        self.counter = 0
    @Decorator
    def method1(self):
        pass

运行后报错:

5 def __call__(self, *args, **kwargs):
----> 6     self.counter += 1
      7     return self.func(*args, **kwargs)

AttributeError: 'Decorator' object has no attribute 'counter'

问题原因

用类装饰器修饰实例方法后,原方法会被替换成装饰器的实例。调用A().method1()时,实际执行的是装饰器实例的__call__方法,此时__call__里的self是Decorator的实例,而非A的实例;而A的实例会作为第一个参数被传入__call__的args列表中。

解决方案

方案1:直接从参数中提取类实例

修改装饰器的__call__方法,从args中获取A的实例(即原方法的self),直接操作该实例的属性:

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(self.func.__name__)
        # args[0]就是类A的实例(原方法的self)
        a_instance = args[0]
        a_instance.counter += 1
        return self.func(*args, **kwargs)


class A:
    def __init__(self):
        self.counter = 0
    @Decorator
    def method1(self):
        pass

# 测试
a = A()
a.method1()
print(a.counter)  # 输出1

方案2:让装饰器实现描述符协议(更规范)

实例方法本质是描述符,让装饰器类实现__get__方法,确保装饰器能正确绑定类实例,这样__call__可以直接拿到A的实例:

from functools import partial

class Decorator:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        # 将类实例绑定到装饰器的调用逻辑中
        return partial(self.__call__, instance)

    def __call__(self, instance, *args, **kwargs):
        print(self.func.__name__)
        instance.counter += 1
        return self.func(instance, *args, **kwargs)


class A:
    def __init__(self):
        self.counter = 0
    @Decorator
    def method1(self):
        pass

# 测试
a = A()
a.method1()
print(a.counter)  # 输出1

说明

两种方案都能实现需求:打印被装饰方法的名称,同时更新A实例的counter属性。方案2更符合Python的描述符机制,尤其在装饰复杂方法时更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:17:32