在Python 3中删除了绑定和非绑定方法的概念。在Python 3中,当您在类中声明方法时,您正在使用def关键字,从而创建了一个函数对象。这是一个常规函数,周围的类用作其命名空间。在下面的示例中,我们f在class中声明method A,它成为一个函数A.f:
class A(object): def f(self, x): return 2 * x A.f # <functionA.fat ...> (in Python 3.x)
在Python 2中,行为有所不同:类中的函数对象被类型为的对象隐式替换,这些对象instancemethod被称为未绑定方法,因为它们未绑定到任何特定的类实例。可以使用.__func__属性访问基础功能。
A.f # <unbound method A.f> (in Python 2.x) A.f.__class__ # <type 'instancemethod'> A.f.__func__ # <function f at ...>
后一种行为通过检查得到了证实-方法在Python 3中被视为函数,而在Python 2中则保持了区别。
import inspect inspect.isfunction(A.f) # 真正 inspect.ismethod(A.f) # 假
import inspect inspect.isfunction(A.f) # 假 inspect.ismethod(A.f) # 真正
在两个版本的Python中A.f,只要您将class的实例A作为第一个参数传递,就可以直接调用函数/方法。
A.f(1, 7) # Python 2:TypeError:未绑定方法f()必须使用 # 一个实例作为第一个参数(取而代之的是int实例) # 的Python 3:14 a = A() A.f(a, 20) # Python 2 & 3: 40
现在假设a是class的实例A,那是a.f什么?好吧,从直觉上讲,这应该是f类的相同方法A,只是应该以某种方式“知道”它已应用于对象a–在Python中,这称为绑定到的方法a。
具体细节如下:编写会a.f调用的魔术__getattribute__方法a,该方法首先检查是否a有一个名为的属性f(没有),然后检查类A是否包含具有该名称的方法(有),并且创建一个新对象m类型的method,其具有的参考原始A.f中m.__func__,向对象的引用a中m.__self__。当将此对象作为函数调用时,它只需执行以下操作:m(...) => m.__func__(m.__self__, ...)。因此,将此对象称为绑定方法,因为在被调用时它知道提供绑定到的对象作为第一个参数。(这些内容在Python 2和3中的工作方式相同)。
a = A() a.f # <bound methodA.fof <__main__.A object at ...>> a.f(2) # 4 # 注意:绑定方法objecta.fis每次都会重新创建一次: a.f isa.f # 假 # 作为性能优化,您可以将绑定方法存储在对象的 # __dict__,在这种情况下,方法对象将保持不变: a.f = a.f a.f isa.f # 真正
最后,Python有类方法和静态方法–特殊方法。类方法的工作方式与常规方法相同,除了在对象上调用它们时,它们将绑定到对象的类而不是对象。这样。当您调用这样的绑定方法时,它将类的作为第一个参数传递。静态方法甚至更简单:它们根本不绑定任何内容,而只是返回基础函数而无需任何转换。m.__self__ = type(a)a
class D(object): multiplier = 2 @classmethod def f(cls, x): returncls.multiplier* x @staticmethod def g(name): print("Hello, %s" % name) D.f # <bound methodtype.fof <class '__main__.D'>> D.f(12) # 24 D.g # <functionD.gat ...> D.g("world") # 你好,世界
请注意,即使在实例上访问,类方法也已绑定到该类:
d = D() d.multiplier = 1337 (D.multiplier, d.multiplier) # (2,1337) d.f # <bound methodD.fof <class '__main__.D'>> d.f(10) # 20
值得注意的是,在最低层次上,函数,方法,静态方法等实际上是调用__get__,__set__和可选的__del__特殊方法的描述符。有关类方法和静态方法的更多详细信息:
Python中的@staticmethod和@classmethod有什么区别?
@classmethod和@staticmethod对初学者的意义?