调用对象函数 - python
调用对象函数 - python
我提出这个问题是因为在这个答案的评论区有一个讨论。我对此有了90%的理解。
In [1]: class A(object): # 名称为'A'的类 ...: def f1(self): pass ...: In [2]: a = A() # 一个实例
f1
以三种不同的形式存在:
In [3]: a.f1 # 绑定方法 Out[3]:> In [4]: A.f1 # 未绑定方法 Out[4]: In [5]: a.__dict__['f1'] # 不存在 KeyError: 'f1' In [6]: A.__dict__['f1'] # 函数 Out[6]:
绑定方法、未绑定方法和函数对象之间有什么区别?如何调用这三个对象?它们如何相互转换?关于这些内容的文档非常难以理解。
在Python中,使用def
语句或lambda
来创建一个函数。在Python 2中,当一个函数出现在class
语句的主体中(或者被传递给type
类的构造函数调用),它会被转换为一个未绑定的方法。当在类实例上访问一个函数时,它被转换为一个绑定方法,并自动将实例作为第一个self
参数传递给方法。
在Python 2中,可以使用type
类的构造函数来创建类:
C2 = type('C2', (object,), {'f1': f1}) C2.f1
还可以手动将f1
转换为未绑定的方法:
import types types.MethodType(f1, None, C)
未绑定的方法可以通过在类实例上访问来绑定:
C().f1
访问被转换为通过描述符协议调用:
C.f1.__get__(C(), C)
综合起来:
types.MethodType(f1, None, C).__get__(C(), C)
或者直接:
types.MethodType(f1, C(), C)
函数和未绑定方法之间的主要区别在于后者知道它绑定到哪个类;调用或绑定未绑定的方法需要其类类型的实例。
Python 3消除了函数和未绑定方法之间的区别;在Python 3中,通过在类实例上访问函数,可以直接得到函数本身。
将函数绑定到实例会将其第一个参数(通常称为self
)固定为该实例。因此,绑定方法C().f1
等效于以下任意一种:
(lamdba *args, **kwargs: f1(C(), *args, **kwargs)) functools.partial(f1, C())
因此,函数和未绑定方法之间的主要区别在于后者支持描述符协议;调用未绑定方法需要一个实例。