我读过Expert Python Programming,它有一个多继承的例子。书的作者已经解释过,但我不明白,所以我想有另一种观点。
该示例显示了该对象 B
创建了两次!
你能给我一个直观的解释吗?
In [1]: class A(object):
...: def __init__(self):
...: print "A"
...: super(A, self).__init__()
In [2]: class B(object):
...: def __init__(self):
...: print "B"
...: super(B, self).__init__()
In [3]: class C(A,B):
...: def __init__(self):
...: print "C"
...: A.__init__(self)
...: B.__init__(self)
In [4]: print "MRO:", [x.__name__ for x in C.__mro__]
MRO: ['C', 'A', 'B', 'object']
In [5]: C()
C
A
B
B
Out[5]: <__main__.C at 0x3efceb8>
书的作者说:
这是因为 A.__init__(self)
打电话,这是用
C实例,从而制作 super(A, self).__init__()
呼叫 B
的构造函数
我没有得到它的想法是如何 A.__init__(self)
打电话会 super(A, self).__init__()
呼叫 B
的构造函数
该 super()
只是意味着“下一行”,其中的行是 MRO ['C', 'A', 'B', 'object']
。所以接下来就行了 A
是 B
。
mro根据称为的算法计算 C3线性化。
当你使用 super()
,Python就是这个顺序。当你写你的课 A
你还不知道接下来会是哪一堂课。只有在您创建了课程之后 C
通过多重继承并运行您的程序,您将获得mro并“知道”下一步将会是什么 A
。
对于您的示例,它意味着:
C()
打电话给 __init__()
的 C
,它称之为 __init__()
的 A
。现在, A
使用 super()
并发现 B
在mro,因此它称之为 __init__()
的 B
。接下来, __init__()
的 C
打电话给 __init__()
的 B
再次。
调用 super()
在里面 __init__()
创建一个不同的mro并避免双重调用 __init__()
的 B
。
from __future__ import print_function
class A(object):
def __init__(self):
print("A")
super(A, self).__init__()
class B(object):
def __init__(self):
print("B")
super(B, self).__init__()
class C(A,B):
def __init__(self):
print("C")
super(C, self).__init__()
使用:
>>> C.mro()
[__main__.C, __main__.A, __main__.B, object]
>> C()
C
A
B
让我们稍微修改一下代码并替换 __init__
同 doit
只是为了确保行为是通用的,与之无关 __init__
。
我们还添加更多输出以查看到底发生了什么:
class A(object):
def doit(self):
print "A", self, super(A, self)
super(A, self).doit()
class B(object):
def doit(self):
print "B", self, super(B, self)
class C(A,B):
def doit(self):
print "C", self
A.doit(self)
B.doit(self)
print "MRO:", [x.__name__ for x in C.__mro__]
#MRO: ['C', 'A', 'B', 'object']
C().doit()
这将输出:
C <__main__.C object at ...>
A <__main__.C object at ...> <super: <class 'A'>, <C object>>
B <__main__.C object at ...> <super: <class 'B'>, <C object>>
B <__main__.C object at ...> <super: <class 'B'>, <C object>>
你看,那 self
实际上是 C
对象无处不在,所以当你击中时 A.doit
你真的有 <super: <class 'A'>, <C object>>
。
这转化为:
对象 C
打电话给 doit
之后的下一个(超级)类的方法 A
来自MRO清单
之后是MRO的下一堂课 A
是 B
,所以我们最终打电话 B.doit()
。
检查此代码:
class C(A,B):
def doit_explain(self):
print "C", self
# calls B.doit()
super(A, self).doit()
print "Back to C"
# calls A.doit() (and super in A also calls B.doit())
super(C, self).doit()
print "Back to C"
# and just B.doit()
B.doit(self)
而不是 A.doit(self)
我用 super(A, self).doit()
直接,它也导致 B.doit()
打电话,这是输出:
C <__main__.C object at ...>
B <__main__.C object at ...> <super: <class 'B'>, <C object>>
Back to C
A <__main__.C object at ...> <super: <class 'A'>, <C object>>
B <__main__.C object at ...> <super: <class 'B'>, <C object>>
Back to C
B <__main__.C object at ...> <super: <class 'B'>, <C object>>