绑定的未绑定和静态方法

在 Python 3删除了绑定和未绑定方法的想法。在 Python 3 中,当你在类中声明方法时,你正在使用 def 关键字,从而创建一个函数对象。这是一个常规函数,周围的类作为其命名空间。在下面的例子中,我们在类 A 中声明方法 f,它变成了一个函数 A.f

Python 3.x >= 3.0

class A(object):
    def f(self, x):
        return 2 * x
A.f
# <function A.f at ...>  (in Python 3.x)

在 Python 2 中,行为是不同的:类中的函数对象被 instancemethod 类型的对象隐式替换,这些对象被称为*未绑定方法,*因为它们未绑定到任何特定的类实例。可以使用 .__func__ 属性访问基础函数。

Python 2.x >= 2.3

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 中则支持这种区别。

Python 3.x >= 3.0

import inspect

inspect.isfunction(A.f)
# True
inspect.ismethod(A.f)
# False

Python 2.x >= 2.3

import inspect

inspect.isfunction(A.f)
# False
inspect.ismethod(A.f)
# True

在 Python 函数/方法的两个版本中,只要你将类 A 的实例作为第一个参数传递,就可以直接调用 A.f

A.f(1, 7)
# Python 2: TypeError: unbound method f() must be called with
#                      A instance as first argument (got int instance instead) 
# Python 3: 14   
a = A()
A.f(a, 20)
# Python 2 & 3: 40

现在假设 aA 的一个实例,那么什么是 a.f 呢?嗯,直觉上这应该是类 A 的相同方法 f,只有它应该以某种方式知道它被应用于对象 a - 在 Python 中这被称为绑定a 的方法。

细节如下:写 a.f 调用 a 的魔法 __getattribute__ 方法,首先检查 a 是否有一个名为 f 的属性(它没有),然后检查类 A 是否包含具有这样名字的方法(确实如此),并创建了一个 method 类型的新对象 m,它引用了 m.__func__ 中的原始 A.f,以及对 m.__self__ 中对象 a 的引用。当此对象作为函数调用时,它只执行以下操作:m(...) => m.__func__(m.__self__, ...)。因此,此对象称为**绑定方法,**因为在调用时,它知道将其绑定的对象作为第一个参数提供。 (这些东西在 Python 2 和 3 中的工作方式相同)。

a = A()
a.f
# <bound method A.f of <__main__.A object at ...>>
a.f(2)
# 4

# Note: the bound method object a.f is recreated *every time* you call it:
a.f is a.f  # False
# As a performance optimization you can store the bound method in the object's
# __dict__, in which case the method object will remain fixed:
a.f = a.f
a.f is a.f  # True

最后,Python 有类方法静态方法 - 特殊类型的方法。类方法的工作方式与常规方法相同,只是在对象上调用它们时,它们绑定到对象的而不是对象的类。因此 m.__self__ = type(a)。当你调用这样的绑定方法时,它会传递 a 的类作为第一个参数。静态方法甚至更简单:它们根本不绑定任何东西,只是返回底层函数而不进行任何转换。

class D(object):
    multiplier = 2

    @classmethod
    def f(cls, x):
        return cls.multiplier * x

    @staticmethod
    def g(name):
        print("Hello, %s" % name)

D.f
# <bound method type.f of <class '__main__.D'>>
D.f(12)
# 24
D.g
# <function D.g at ...>
D.g("world")
# Hello, world

请注意,即使在实例上访问,类方法也绑定到类:

d = D()
d.multiplier = 1337
(D.multiplier, d.multiplier)
# (2, 1337)
d.f
# <bound method D.f of <class '__main__.D'>>
d.f(10)
# 20

值得注意的是,在最低级别,函数,方法,静态方法等实际上是调用 __get____set__和可选的 __del__ 特殊方法的描述符 。有关 classmethods 和 staticmethods 的更多详细信息: