6

Python 的 super() 如何与多重继承一起工作?

我在看上面的问题/答案,让自己很困惑

 53 class First(object):
 54     def __init__(self):
 55         print "first"
 56
 57 class Second(First):
 58     def __init__(self):
 59         super(Second, self).__init__()
 60         print "second"
 61
 62 class Third(First):
 63     def __init__(self):
 64         print "third"
 65
 66 class Fourth(Second, Third):
 67     def __init__(self):
 68         super(Fourth, self).__init__()
 69         print "thats it"

第四()
第三

就是这样

 53 class First(object):
 54     def __init__(self):
 55         print "first"
 56
 57 class Second(First):
 58     def __init__(self):
 59         #super(Second, self).__init__()         <---- commented out
 60         print "second"
 61
 62 class Third(First):
 63     def __init__(self):
 64         print "third"
 65
 66 class Fourth(Second, Third):
 67     def __init__(self):
 68         super(Fourth, self).__init__()
 69         print "thats it"

第四()
第二
就是这样

有人可以向我解释一下幕后发生的事情,为什么顶部打印件"third"和底部打印件没有?

我觉得在幕后发生了某种我没有看到的顺序/顺序。

- 第四。人事部


在 Second (, , , , )中注释掉 super

超级秒
(, , , , )

4

2 回答 2

5

super实际上并没有调用超类。它根据方法解析顺序 (MRO) 调用下一个方法。您的示例类的 MRO 看起来如下:

Fourth
Second
Third
First

也就是说,使用superfromFourth可以为您提供一个方法 on Second。使用superfrom 为Second您提供了一种方法Third。等等

在第一个示例中:

  1. Fourth.__init__叫做。
  2. Fourth.__init__Second.__init__通过调用super
  3. Second.__init__Third.__init__通过调用super
  4. Third.__init__打印“第三”
  5. Second.__init__打印“第二”
  6. Fourth.__init__打印“就是这样”。

在第二个例子中:

  1. Fourth.__init__叫做。
  2. Fourth.__init__Second.__init__通过调用super
  3. Second.__init__打印“第二”
  4. Fourth.__init__打印“就是这样”。

所以,是的,改变一个super调用会Second改变是否调用了某些东西Third,即使Third它不是Second. 这确实令人困惑。我推荐阅读“Python's Super is nifty, but you can't use it”。这就是我读到的解释,使上述内容对我有意义。

于 2013-10-14T17:43:03.617 回答
4

MRO 不是嵌套层次结构。它是一个遵循一组约束的平面列表,即每个类必须在其基类之前,并且这些基类必须以与子类声明中提到的相对于彼此相同的顺序存在。

通过打印Fourth.__mro__,我们可以看到您的示例中的 MRO 是:

(<class '__main__.Fourth'>, 
<class '__main__.Second'>, 
<class '__main__.Third'>, 
<class '__main__.First'>, 
<type 'object'>)

对它的每次调用super都会调用 MRO 中的下一个方法。您可以将super呼叫次数视为您将下降到的 MRO 的零索引“深度”。

由于super在第一个片段中有两个调用,Second.__init__并且Third.__init__被调用(当然,还有直接类的 init 方法)。同样,在第二个代码段中,您对 进行了一次调用super,这意味着只会Second.__init__调用。

于 2013-10-14T17:49:47.167 回答