有关完整详细信息,请参阅此博客文章。但我可以在这里总结一下。
关键是理解绑定方法。绑定方法只是一个包含实际函数对象的对象,以及它绑定到的实例。像这样的东西:
class BoundMethod(object):
def __init__(self, function, instance):
self.__func__ = function
self.__self__ = instance
def __call__(self, *args, **kwargs):
return self.__func__(self.__self__, *args, **kwargs)
绑定方法是一流的对象,因此您可以传递它们并检查它们:
>>> class C:
... def foo(self):
... print(self)
>>> C.foo
<function __main__.foo>
>>> c = C()
>>> c.foo
<bound method C.foo of <__main__.C object at 0x10ab90a90>>
>>> c.foo.__func__
<function __main__.foo>
>>> c.foo.__func__ is C.foo, c.foo.__self__ is c
(True, True)
你甚至可以手动构建它们:
>>> import types
>>> f = types.MethodType(C.foo, 2)
>>> f
<bound method int.foo of 2>
>>> f()
2
(虽然我上面的 Python 类显然不是真正的代码,但它并不遥远;如果你做一些愚蠢的事情,比如尝试绑定绑定方法或不可调用的方法,你甚至会得到大部分相同的错误。)
那么,c.foo
最终如何绑定c
?要真正理解这一点,您需要了解描述符。但简短的版本是这样的:
Python 中几乎每种类型都有一个额外的方法__get__
。这用于属性访问。基本上,当您键入 时c.foo
,它会执行以下操作(忽略基类、插槽、getattr 覆盖等):
try:
return c.__dict__['foo']
except KeyError:
value = type(c).__dict__['foo']
try:
return value.__get__(c)
except AttributeError:
return value
函数对象上的__get__
方法返回一个绑定方法(绑定到它的参数)。
所以,回到你的例子,显然B(A()).show_name()
打印出关于A
因为B(A()).show_name
被绑定到一个A
实例的东西......但是这是怎么发生的?
好吧,让我们追溯一下:
>>> a = A()
>>> b = B(a)
>>> b.show_name
在你的__init__
函数中,你这样做:
self.show_name = a.show_name
那只是将已经绑定的方法复制a.show_name
到普通的实例变量self.show_name
中。因此,当您稍后查找时b.show_name
,它是相同的绑定方法,绑定到a
. 如果要重新绑定它,则必须手动进行,例如:
self.show_name = types.MethodType(a.show_name.__func__, self)