与实例的绑定发生在您访问 c.func
时,而不是在您调用它时。当您这样做c.func = c.func
时,右侧的属性访问由类处理C
并评估为绑定方法。重新分配它以c.func
将其分配给实例,但它已经是一个绑定方法,所以这不会改变行为。
在您的 newfunc 示例中,您只是定义了一个函数并对其进行了分配,因此它从未被制成实例方法。由于您将其直接分配给实例,因此该类没有机会拦截访问并将其包装在实例方法中。
您可以在任何您喜欢的地方分配绑定方法,并且它仍然绑定到您获取它的实例。请参阅以下示例:
>>> class C(object):
... def __init__(self, name):
... self.name = name
... def func(self, a):
... print("Called {0} with {1}".format(self.name, a))
>>> one = C("one")
>>> two = C("two")
>>> one.func(1)
Called one with 1
>>> two.func(1)
Called two with 1
>>> one.func2 = two.func
>>> one.func2(1)
Called two with 1
请注意,一旦我分配one.func2 = two.func
,调用one.func2
将调用绑定到的实例方法two
,而不是one
。这是因为当我访问 时two.func
,我得到了一个绑定到该实例的方法。我以后将它分配到哪里都没有关系。它仍然绑定到访问它的实例。
如果您直接访问未绑定的方法并尝试将其分配到别处,则会收到 TypeError,因为该方法从未绑定:
>>> one.func3 = C.func
>>> one.func3(1)
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
one.func3(1)
TypeError: unbound method func() must be called with C instance as first argument (got int instance instead)
另请注意,如果您将方法添加到类,它会在实例上调用时起作用,即使该实例是在您将方法添加到类之前创建的。保持与one
以前相同的对象,我可以这样做:
>>> def newFunc(self, a):
... print("Newfunc of {0} called with {1}".format(self.name, a))
>>> C.newFunc = newFunc
>>> one.newFunc(1)
Newfunc of one called with 1
为了简洁地回答您的问题,c.func
必须绑定c
ifc
是具有方法的类的实例func
,并且c
本身没有实例属性func
。(如果c
确实有同名的实例属性,则会覆盖类一,因此该类不会进行包装以将方法绑定到实例。)