多重继承:包含super()调用的重写方法

时间:2017-09-03 20:46:49

标签: python

使用文件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()时,我预计会发生以下情况:

  1. 执行m D的第一行,从而输出"m of D called"
  2. 第二行super().m()已执行,首先将我们带到m的{​​{1}}。
  3. B的{​​{1}}中,首先输出m,然后B "m of B called"由于m调用而被执行在A的{​​{1}}中,输出super.m()
  4. m的{​​{1}}以类似于3的方式执行。
  5. 如您所见,我期望看到的是:

    B

    为什么我错了? python是否以某种方式跟踪特定超类的"m of A called"次调用并将执行限制为1?

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,因此任何多重继承的情况都提供了多个到达对象的路径。 为了防止多次访问基类,动态算法将搜索顺序线性化,以保留每个类中指定的从左到右的顺序,只调用每个父类一次,这是单调的(意味着可以在不影响其父项的优先顺序的情况下对类进行子类化。)总之,这些属性可以设计具有多重继承的可靠且可扩展的类。