使用文件super5.py:
class A:
def m(self):
print("m of A called")
class B(A):
def m(self):
print("m of B called")
super().m()
class C(A):
def m(self):
print("m of C called")
super().m()
class D(B,C):
def m(self):
print("m of D called")
super().m()
我们可以做到以下几点:
>>> from super5 import D
>>> x = D()
>>> x.m()
m of D called
m of B called
m of C called
m of A called
对我来说,这没有意义,因为当我执行x.m()
时,我预计会发生以下情况:
m
D
的第一行,从而输出"m of D called"
。super().m()
已执行,首先将我们带到m
的{{1}}。B
的{{1}}中,首先输出m
,然后B
"m of B called"
由于m
调用而被执行在A
的{{1}}中,输出super.m()
。m
的{{1}}以类似于3的方式执行。如您所见,我期望看到的是:
B
为什么我错了? python是否以某种方式跟踪特定超类的"m of A called"
次调用并将执行限制为1?
答案 0 :(得分:4)
不,Python会在特殊的__mro__
属性(新式类中的方法解析顺序)中跟踪所有超类:
print(D.__mro__)
你得到:
(<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
因此,当您致电super
时,它会依次按此列表。
请参阅此问题:What does mro() do?。
在"Multiple Inheritance"一章的官方文件中解释了所有内容。
在大多数情况下,在最简单的情况下,您可以将从父类继承的属性的搜索视为深度优先,从左到右,而不是在同一个类中搜索两次,其中重叠层次结构。因此,如果在DerivedClassName中找不到属性,则在Base1中搜索它,然后(递归地)在Base1的基类中搜索,如果在那里找不到,则在Base2中搜索它,依此类推。
事实上,它稍微复杂一些;方法解析顺序动态变化以支持对super()的协作调用。这种方法在一些其他多继承语言中称为call-next-method,并且比单继承语言中的超级调用更强大。
动态排序是必要的,因为多重继承的所有情况都表现出一个或多个菱形关系(其中至少有一个父类可以通过最底层的多个路径访问)。例如,所有类都继承自object,因此任何多重继承的情况都提供了多个到达对象的路径。 为了防止多次访问基类,动态算法将搜索顺序线性化,以保留每个类中指定的从左到右的顺序,只调用每个父类一次,这是单调的(意味着可以在不影响其父项的优先顺序的情况下对类进行子类化。)总之,这些属性可以设计具有多重继承的可靠且可扩展的类。