考虑以下代码:
class A:
def __init__(self, data):
self.data = data
def f(self):
print('from A', self.data)
a = A(20)
def fnew(self):
print('new from A', self.data)
A.f = fnew
print(a.f.__func__ is A.f)
输出为True,但我预计它是假的。这就是为什么:根据我的理解,每次从C类创建一个对象O时,它以类型'方法'的对象形式继承C的所有函数属性。每个这样的方法对象都具有属性O和相应的函数。在这种情况下,a.f具有对象a的属性和具有名称&f;#39;的函数。但是当执行A.f = fnew时,我只是改变了类对象A的属性,而不是方法对象a.f的属性,那么a.f. func 的结果到底是怎么改变的呢?
答案 0 :(得分:3)
执行a.f
时,Python会从实例f
中查找成员a
。当它找不到具有该名称的成员时,它将查找类型层次结构以查找它。所以在这种情况下,它将查看实例的类型,即A
。这就是为什么访问a.f
将使用A.f
中存储的函数。
如果要在实例中覆盖f
,则不会发生这种情况:
>>> A.f = fnew
>>> a.f
<bound method fnew of <__main__.A object at 0x00000083E819B1D0>>
>>> a.f = 'foo'
>>> a.f
'foo
请注意,在创建实例时,该类型的成员将不复制到该实例。如果发生这种情况,那将导致创建对象的实例非常昂贵。相反,类型系统只会在实例没有自己的成员时从类型中查找成员。
正如评论中的timgeb所述,在Python 2中,您的最终检查a.f.__func__ is A.f
将返回False
。这是因为A.f
将返回未绑定函数,该函数与原始函数不同。但这只是一个小细节,不会改变我上面写的内容:该方法仍然会从类型中查找。