Class 通过带有两个参数的 super 继承

Class inheritance via super with two arguments

在下面的代码中,我用数字替换了 args 以演示 类 是继承的。

class Animal:
  def __init__(self, animalName):
    print(animalName, 'is an animal.');

class Mammal(Animal):
  def __init__(self, mammalName):
    print(mammalName, 'is a mammal.')
    super().__init__(mammalName)

class CannotFly(Mammal):
  def __init__(self, mammalThatCantFly):
    print('2', "cannot fly.")
    super().__init__('2')

class CannotSwim(Mammal):
  def __init__(self, mammalThatCantSwim):
    print('1', "cannot swim.")
    super().__init__('1')

# Cat inherits CannotSwim and CannotFly
class Cat(CannotSwim, CannotFly):
  def __init__(self):
    print('I am a cat.');
    super().__init__('Cat')

cat = Cat()

returns

I am a cat.
1 cannot swim.
2 cannot fly.
2 is a mammal.
2 is an animal.

为什么不是下面的?

I am a cat.
1 cannot swim.
1 is a mammal.
1 is an animal.
2 cannot fly.
2 is a mammal.
2 is an animal.

实际上有两个调用流,不是吗?

看看这个postWhat does 'super' do in Python? - difference between super().__init__() and explicit superclass __init__()

现在它说的是实例的 mro 中的每个 class 都会调用 __init__。 您可以通过执行 print(Cat.__mro__) 来打印它,这将打印出

(<class '__main__.Cat'>, <class '__main__.CannotSwim'>, <class '__main__.CannotFly'>, <class '__main__.Mammal'>, <class '__main__.Animal'>, <class 'object'>)

如您所见,存在调用顺序。现在,为什么使用“2”而不是“1”,请参阅 hussic

评论中的答案

您可以看到 Cat 的方法解析顺序 (MRO):

>>> Cat.mro()
[<class '__main__.Cat'>, <class '__main__.CannotSwim'>, <class '__main__.CannotFly'>, <class '__main__.Mammal'>, <class '__main__.Animal'>, <class 'object'>]

由于 C3 linearization algorithm,每个 class 在 MRO 中出现 一次 。简而言之,这使用一些简单的规则从继承图中构造了 MRO:

  1. 图中每个 class 出现一次。
  2. 每个 class 在其任何 parent class 之前。
  3. 当一个 class 有两个 parent 时,将保留 parent 的 left-to-right 顺序。

(“线性化”,因为它产生了继承图中节点的线性排序。)

super() 命名错误;更好的名字应该是谎言 nextclass,因为它 而不是 使用当前 class 的 parent 列表,但是 MRO self 参数。当您呼叫 Cat 时,您会看到以下呼叫。

  1. Cat.__init__
  2. Cat.__init__ 使用 super 调用 CannotSwim.__init__
  3. CannotSwim.__init__ 使用 super 调用 CannotFly.__init__
  4. CannotFly.__init__ 使用 super 调用 Mammal.__init__
  5. Mammal.__init__ 使用 super 调用 Animal.__init__
  6. Animal.__init__ 使用 super 调用 object.__init__

object.__init__ 不使用 super(它“拥有”__init__),所以链到此结束。

特别注意 #3:CannotSwim 会导致使用继承图中的“兄弟”,而不是它自己的 parent。