import inspect
inspect.isfunction(A.f)
#假
inspect.ismethod(A.f)
#真正
在两个版本的Python中A.f,只要您将class的实例A作为第一个参数传递,就可以直接调用函数/方法。
A.f(1, 7)
#Python2:TypeError:未绑定方法f()必须使用
#一个实例作为第一个参数(取而代之的是int实例)
#的Python3: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__,...)。因此,将此对象称为绑定方法,因为在被调用时它知道提供绑定到的对象作为第一个参数。(这些内容在Python2和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对初学者的意义?