python继承和在派生类的父类中使用super()

python diamond inheritance and the use of super() in the parents of the derived class

首先,我要为没有更好的头衔道歉。如果你找到一个更合适的,可以随意改变它。

基本上,我被Python的多重继承行为所困扰。在我之前的问题中,我直接阅读了python的c3 mro。这真的有助于我更好地理解Python中的多重继承。就在我认为我掌握了它的时候,我碰到了下面的场景,我似乎无法理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class UltimateBase(object):
    def check(self):
        print 'base check'

class AMixin1(UltimateBase):
    def check(self):
        print 'check A'

class BMixin1(UltimateBase):
    def check(self):
        print 'check B'

class CMixin1(UltimateBase):
    def check(self):
        print 'check C'

class AMixin2(UltimateBase):
    def check(self):
        print 'check A'
        return super(AMixin2, self).check()

class BMixin2(UltimateBase):
    def check(self):
        print 'check B'
        return super(BMixin2, self).check()

class CMixin2(UltimateBase):
    def check(self):
        print 'check C'
        return super(CMixin2, self).check()

class MyView1(AMixin1, BMixin1, CMixin1):
    pass

class MyView2(AMixin2, BMixin2, CMixin2):
    pass

class MyView3(AMixin1, BMixin2, CMixin2):
    pass

class MyView4(AMixin2, BMixin1, CMixin2):
    pass

class MyView5(AMixin2, BMixin2, CMixin1):
    pass

class MyView6(AMixin1, BMixin1, CMixin2):
    pass

class MyView7(AMixin1, BMixin2, CMixin1):
    pass

class MyView8(AMixin2, BMixin1, CMixin1):
    pass

myview1 = MyView1()
myview2 = MyView2()
myview3 = MyView3()
myview4 = MyView4()
myview5 = MyView5()
myview6 = MyView6()
myview7 = MyView7()
myview8 = MyView8()

myview1.check()
print '------------------------'
myview2.check()
print '------------------------'
myview3.check()
print '------------------------'
myview4.check()
print '------------------------'
myview5.check()
print '------------------------'
myview6.check()
print '------------------------'
myview7.check()
print '------------------------'
myview8.check()
print '------------------------'

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
check A
------------------------
check A
check B
check C
base check
------------------------
check A
------------------------
check A
check B
------------------------
check A
check B
check C
------------------------
check A
------------------------
check A
------------------------
check A
check B
------------------------

我可以根据观察结果来追踪一个模式,但它使我无法理解这个结果背后的基本原理。

我有一些问题,例如,为什么myview2.check()会返回

1
2
3
4
check A
check B
check C
base check

1
2
check A
base check

在我看来,我缺少一个关于多重继承的关键部分。请替我填补这个空缺。


当调用myview2.check()时,它遍历兄弟类,然后调用基类。每当这些遍历中的一个到达AMixin1BMixin1CMixin1时,它就会停止,因为这些类不调用super(..., self).check()

正如Benn指出的,这在官方的Python文档中进行了描述。如果你想一想,就必须这样做。子类将假定在子类调用super()之前不调用基类方法。如果是这样(或者更糟的是,如果它取决于它的兄弟姐妹被列出的顺序),它会使事情变得很难处理。


试着把我的脑袋转过来问同样的问题。我发现以下代码有助于简化问题:

(基本上,当所有的super被一个类击中时,该类就会被调用。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A:
  def f(self):
    print("............A: the common base of B and C")

class B(A):
  def f(self):
    print("........B: the left base of D")
    super().f()

class C(A):
  def f(self):
    print("........C: the right base of D")
    super().f()

class D(B,C):
  def f(self):
    print("....D: the top class")
    super().f()

d = D()

d.f()

输出:

1
2
3
4
....D: the top class
........B: the left base of D
........C: the right base of D
............A: the common base of B and C

尝试联机