相关代码 1:
class A(object):
def show(self):
print ('init A...')
class B(A):
def show(self):
super(B, self).show()
print('init B...')
class C(A):
def show(self):
# super(C, self).show()
print('init C...')
class D(B, C):
def show(self):
super(D, self).show()
print('init D...')
d = D()
d.show()
输出的结果是:
init C...
init B...
init D...
这里想问的是为什么没有经过 A,输出 init A...
相关代码 2:
class A(object):
def show(self):
print ('init A...')
class B(A):
def show(self):
super(B, self).show()
print('init B...')
class C(A):
def show(self):
# super(C, self).show()
print('init C...')
class D(C, B): #继承类和代码 1 中的顺序相反
def show(self):
super(D, self).show()
print('init D...')
d = D()
d.show()
输出的结果是:
init C...
init D...
这里想问的是为什么 B 中的方法没有被调用? 还有的就是新式类的 MRO 算法采用广度优先搜索。在这里是怎么调用的?
谢谢各位大佬
1
Outliver0 2018-11-13 09:40:16 +08:00
你可以打印一下__mro__查看顺序
|
2
coroutine 2018-11-13 09:51:09 +08:00
对于, “为什么没有经过 A,输出 init A... ” 你可以参考 Python Cookbook,第 8 章关于 super 的描述。 类 B 里 show 的 super,实际上调用的是类 C 的 show。 而类 C 的 super 已经被你注释掉了。
|
3
Outliver0 2018-11-13 09:52:13 +08:00 2
第一次的 mro 顺序为
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>], super(D, self).show()----> super(B, self).show()------>C.show() C 已经有 show()方法,所有打印顺序为 init C...,init B...,init D... 第二次的 mro 顺序为 [<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>], super(D, self).show() ----->C.show() C 已经有 show()方法,所有打印顺序为 init C... ,init D... |
4
coroutine 2018-11-13 09:58:48 +08:00 1
super 的调用顺序实际上,与最终该类的 MRO 的顺序有关。你可以从 D.__mro__ 打印出类 D 的类继承顺序。
比如您给出的两个例子,的 MRO 分别为 (__main__.D, __main__.B, __main__.C, __main__.A, object); (__main__.D, __main__.C, __main__.B, __main__.A, object) 如何生成 MRO 顺序,就是 cookbook 里提到的 https://en.wikipedia.org/wiki/C3_linearization 了。 |
5
coroutine 2018-11-13 10:01:31 +08:00
您可以参阅 Python Cookbook Chapter 8: 8.7: Calling a Method on a Parent Class 这一小节。
|
6
liukeai7777 2018-11-13 10:11:52 +08:00 1
D 的 mro 是 (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
init C... init B... init D... 所以 super 方法的查找顺序就 DBCA 多以第一个例子 第一步运行到 class D 的 show 方法 , class D show 第一句: [super(D, self).show() 查找 B 的 show 方法。运行到 class B 的 show 方法,classB show 执行第一句:super(B, self).show() 然后又找到 class C 的 show 方法 于是打印第一句 init C,执行第二句 init C ] class D 的 show 第二句 打印 init C 同理第二个例子 MRO 是 DCBA |
7
king1101 OP 多谢各位大佬,我已经理解了,其实走入了一个误区,认为 super 就是调用父类的方法,其实 super 指的是 MRO 的下一个类,和父类没有实质关联。
|
8
zxcvsh 2018-11-13 10:13:14 +08:00 via iPhone 1
百度一下,拓扑排序,好像是这个关键字;图解说明继承检索的顺序很明了
|
9
liukeai7777 2018-11-13 10:13:21 +08:00
D 的 mro 是 (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
init C... init B... init D... 所以 super 方法的查找顺序就 DBCA 多以第一个例子 第一步运行到 class D 的 show 方法 , class D show 第一句: [super(D, self).show() 查找 B 的 show 方法。运行到 class B 的 show 方法,classB show 执行第一句:super(B, self).show() 然后又找到 class C 的 show 方法 于是打印第一句 init C,执行第二句 init B] class D 的 show 第二句 打印 init D 同理第二个例子 MRO 是 DCBA |
10
seven777 2018-11-13 14:57:56 +08:00
给楼主一个解药:
(我不是程序员,但我觉得如此...) 无论当前的任何编程语言,原理基本想通; 虽然不同语言有不同的“继承”处理方式,但原理相同。 统一标准是: 1,没有什么需求非得复杂的继承来实现,如果有,你设计错了; 2,如果一个继承关系你搞不明白,不是你技术问题,是设计错了,换思路吧; 3,“事不过三”在编程中应该是重要思想,比如继承层级不要超过三层,继承源头不要超过三个,再比如 if,while,等判断关系嵌套不要超过三层... 我瞎说的,但觉得应该如此 |
11
ticotico 2018-11-13 15:57:49 +08:00 via Android
不是把 C 中 super 注释掉了么,D 中的 super 是按 mro 查找 MRO 中下一位的,MRO 在新式类中按的是 bfs 来拍得,最近刚接触 mro 不知道说得对不对,各位大佬轻拍
|
12
RomanCavalry 2018-11-15 15:00:16 +08:00
这个就需要了解 Python MRO 的历史了,参考: http://python.jobbole.com/85685/
|