仅在分配时才出现奇怪的 AttributeError

ynn*_*ynn 7 python decorator

我正在实现什么是函数内静态变量的 Python 等效项中描述的装饰器?. 在答案中,装饰器被置于一个正常的功能上,它也在我的环境中工作。

现在我想把装饰器放到一个类方法上。

源代码:

#decorator
def static_variabls(**kwargs):
    def new_func(old_func):
        for key in kwargs:
            setattr(old_func, key, kwargs[key])
        return old_func
    return new_func

class C:
    @static_variabls(counter = 1)
    def f_(self) -> None:
        print(self.f_.counter)
        self.f_.counter += 1

c1 = C()
c1.f_()
c1.f_()
c1.f_()
Run Code Online (Sandbox Code Playgroud)

预期结果:

1
2
3
Run Code Online (Sandbox Code Playgroud)

实际结果:

1
Traceback (most recent call last):
  File "1.py", line 16, in <module>
    c1.f_()
  File "1.py", line 13, in f_
    self.f_.counter += 1
AttributeError: 'method' object has no attribute 'counter'
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这段代码不起作用。根据错误消息,self.f_.counter不存在但print(self.f_.counter)有效。这里发生了什么事?

che*_*ner 0

c1.f_()相当于C.f_.__get__(c1, C)()(由于描述符协议)。__get__返回method实际被调用的对象。您附加counter到原始函数对象,这不是包装的内容method:它包装了 . 创建的函数def new_func。

请注意,使用更简单的装饰器也有同样的问题,它对属性及其初始值进行硬编码。

def add_counter(f):
    f.counter = 1
    return f


class C:
    @add_counter
    def f_(self) -> None:
        print(self.f_.counter)
        self.f_.counter += 1
Run Code Online (Sandbox Code Playgroud)

甚至没有装饰器:

class C:
    def f_(self) -> None:
        print(self.f_.counter)
        self.f_.counter += 1

    f_.counter = 1
Run Code Online (Sandbox Code Playgroud)