调用对象函数 - python

11 浏览
0 Comments

调用对象函数 - 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]: 

绑定方法、未绑定方法和函数对象之间有什么区别?如何调用这三个对象?它们如何相互转换?关于这些内容的文档非常难以理解。

0
0 Comments

在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())

因此,函数和未绑定方法之间的主要区别在于后者支持描述符协议;调用未绑定方法需要一个实例。

0