钻石继承和 MRO

Diamond inheritance and the MRO

我是 MRO 的新手,在弄清楚这些输出的逻辑时遇到问题。

案例一:

class A(object):
  def save(self):
      print "A"

class B(A):
    def save(self):
        print "B"
        super(B, self).save()

class C(A):
  def save(self):
      print "C"
      super(C, self).save()


class D(C, B):
    def save(self):
        print "D"
        super(D,self).save()

D().save()

输出:

D
C
B
A

我的问题是 super(C) 如何调用 B.save()

根据 MRO:super(C, self) 不是关于 "base class of C",而是关于 C 的 MRO 列表中的下一个 class。但是 C.

的 MRO 列表中没有 B

案例二:

class A(object):
  def save(self):
      print "A"

class B(A):
    def save(self):
        print "B"
        super(B, self).save()

class C(A):
  def save(self):
      print "C"
      # removed super call here

class D(C, B):
    def save(self):
        print "D"
        super(D,self).save()

D().save()

输出:

D
C

案例三:

class A(object):
  def save(self):
      print "A"

class B(object):
    #inherits object now instead of A
    def save(self):
        print "B"
        super(B, self).save()

class C(A):
  def save(self):
      print "C"
      super(C, self).save()

class D(C, B):
    def save(self):
        print "D"
        super(D,self).save()

D().save()

输出:

D
C
A

问题

如果 B 不是从 A 继承,而是直接从 object 继承,MRO 会受到怎样的影响?

有人可以解释这背后的原因吗?

为了解决这些问题,您首先需要了解 MROsuper() 是如何工作的。

MRO Python Document - MRO
在Python中,MRO是基于C3线性化的。 (wiki和python文档中有很多例子)

super()(查看Python文档-super())
根据 Python 文档,它说..

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

因此,super()会根据MRO (classobject.__mro__) 进行搜索,并且会被任何一方满足class 或同级 class 类型。

回到你的案例,
案例一
D.__mro__ = (D, C, B, A, object)
因此,输出将是 D C B A

案例二
D的MRO与情况1中的D相同。((D, C, B, A, object))
但是,super()会在C处停止,或者满足,因为classC中的save()没有实现了超级函数调用。

案例三
D的MRO等于(D, C, A, B, object)。因此,当 super() 到达 class A 中的 save() 函数时,它会认为满足。这就是为什么 B 中的保存函数从未被调用过的原因。

另外,如果将D的继承顺序从C、B改为B、C。(class D(C, B)改为class D(B, C))。然后,当您调用 D().save() 时,输出将是 D B 因为 D.__mro__ = (D, B, C, A, object) 和 super() 将在 class B 处得到满足。

此外,根据我的理解,super() 不是强制子 class 对象调用 all 的函数覆盖父 classes 中的函数。如果你想强制你的 class 调用其父 classes 中的所有覆盖函数。您可以尝试执行以下操作:

class Base(object):
    def method(self):
        print('Base-method')

class Parent(object):
    def method(self):
        print('Parent-method')

class Child(Parent):
    def method(self):
        print('Child-method')
        super(Child, self).method()

class GrandChild(Child, Base):
    def method(self):
        print('GrandChild-method')
        for base in GrandChild.__bases__:
            base.method(self)
        #super(GrandChild, self).method()

然后,当您调用 `GrandChild().method() 时,输出将是:

GrandChild-method
Child-method
Parent-method
Base-method

注:
GrandChild.__bases__ 仅包含 class 子项和 class 基础

PS.
上面说 满意 ,我的意思是不再有 super() 调用。