python - 装饰器和类方法

标签 python class methods decorator python-decorators

我无法理解为什么会发生以下情况。我有一个装饰器,它除了检查函数是否是方法之外什么都不做。我以为我已经理解了 Python 中的方法是什么,但显然情况并非如此:

import inspect

def deco(f):
    def g(*args):
        print inspect.ismethod(f)
        return f(*args)
    return g

class Adder:
    @deco
    def __call__(self, a):
        return a + 1

class Adder2:
    def __call__(self, a):
        return a + 2
Adder2.__call__ = deco(Adder2.__call__)

现在,运行以下命令:

>>> a = Adder()
>>> a(1)
False
2
>>> a2 = Adder2()
>>> a2(1)    
True
3

我希望这段代码打印两次 True。

那么,像在 Adder2 中那样手动装饰函数不完全等同于通过 @deco 函数进行装饰?

有人可以这么高兴并解释为什么会发生这种情况吗?

最佳答案

方法是与类相关联的函数。仅当您从已定义的类中检索方法时才会创建方法;方法是函数的包装器,同时也引用了类(也可以选择引用实例)。

第一种情况发生的是:Python 编译你的类定义Adder。它找到装饰器定义和一个函数。装饰器被传递给函数,返回一个 new 函数。该函数被添加到类定义中(存储在类 __dict__ 中)。一直以来,您都在处理一个 python 函数,不是一个方法。这会在以后发生。

当您随后调用 a(1) 时,查找显示该实例没有 __call__Adder 类有,因此使用 __getattribute__() 检索它.这会找到一个 function(你的 deco 装饰器),它是一个 descriptor所以它是__get__()方法被调用(so Adder.__call__.__get__(a, Adder)),返回一个绑定(bind)的方法,然后在1值。该方法是绑定(bind)的,因为当调用 __get__()instance 不是 None 。您的装饰器在类构建时包装了一个函数,它打印 False 因为它传递了一个未包装的函数以开始。

然而,在第二种情况下,您检索一个方法(再次通过 __getattribute__() 在未修饰的 Adder2.__call__ 上调用 __get__() > 函数),这次未绑定(bind)(因为没有实例,只有一个类传递给 __get__() (完整的调用是 Adder2.__call__.__get__(None, Adder2)),然后你然后装饰那个方法。现在 ismmethod() 打印 True。

请注意,在 Python 3 中,后一种情况发生了变化。在 Python 3 中不再有未绑定(bind)方法的概念,只有函数和绑定(bind)方法。因此,“绑定(bind)”一词被完全删除。您的第二种情况也会打印 False 因为 Adder2.__call__.__get__(None, Adder2) 在这种情况下返回一个函数。

关于python - 装饰器和类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12493074/

相关文章:

java - 在同一个Java数组中调用扩展类函数

c# - 何时使用 this.method()?

python - 如何让系统实现RFID卡二次读取退出?

python - 使用 VectorAssembler 计算平均值和最大值

Python 多处理关键字参数

python - 在Python中,对象有自己的类变量副本吗?

c++ - 编译崩溃 - 在另一个成员函数中使用一个成员函数

java - 出现奇怪的 java.lang.NoSuchMethodError 错误

python - 如何在Python中基于列表元素创建MySQL表?

java - 最后的预期计算与测试仪不匹配。我的 setDimensions 方法有什么问题吗?