本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。
个人其他博客地址:
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
我们知道在python在类根据不同的版本有不同的定义且对应的使用的算法不同:
多继承中引发的MRO在旧版本里使用的深度优先算法,这里暂时不去探究。
MRO是出现在面向对象变成语言中关于继承的对象中一个查询相关属性和方法的定位搜索算法。
大白话的意思就是:我继承多个父类的时候,调用相关的方法的是,如何快速知道我要调用的父类的那个方法(或者我自身的方法)。
多继承情况下,各自的父类的属性和方法都各自为政。因此也出现所谓一个【菱形继承】的问题。
如图示:
在【菱形继承】图示里,子类进行相关的方法调用的时候,如果确定是调用哪个父类的方法的时候就需要一个调度算法去搜索定位,所以这个搜索的顺序就是MRO。
在解决【菱形继承】的问题里,我们判断mro需要先确定一个线性序列,然后查找路径由由序列中类的顺序决定。在python3中,使用了C3算法,C3算法就是生成一个线性序列。
Python提供了__mor__和mor() 来查看类的方法解析顺序
首先我们的【菱形继承】图示如:
转为我们代码为:
class A1: pass
class A2: pass
class A3: pass
class B1(A1,A2): pass
class B2(A2): pass
class B3(A2,A3): pass
class C1(B1): pass
class C2(B1,B2): pass
class C3(B2,B3): pass
class D(C1, C2, C3): pass
for s in D.__mro__:
print(s)
输出的结果为:
<class '__main__.D'>
<class '__main__.C1'>
<class '__main__.C2'>
<class '__main__.B1'>
<class '__main__.A1'>
<class '__main__.C3'>
<class '__main__.B2'>
<class '__main__.B3'>
<class '__main__.A2'>
<class '__main__.A3'>
<class 'object'>
从左到右的分析
左右对比
文字说明:
先明确几个查询点:
class A1: pass
class A2: pass
class A3: pass
class B1(A1,A2): pass
class B2(A2): pass
class B3(A2,A3): pass
class C1(B1): pass
class C2(B1,B2): pass
class C3(B2,B3): pass
class D(C1, C2, C3): pass
print("从D开始查找:")
for i,s in enumerate( D.__mro__):
print("第"+str(i+1)+"轮:",s)
输出结果Wie:
从D开始查找:
第1轮: <class '__main__.D'>
第2轮: <class '__main__.C1'>
第3轮: <class '__main__.C2'>
第4轮: <class '__main__.B1'>
第5轮: <class '__main__.A1'>
第6轮: <class '__main__.C3'>
第7轮: <class '__main__.B2'>
第8轮: <class '__main__.B3'>
第9轮: <class '__main__.A2'>
第10轮: <class '__main__.A3'>
第11轮: <class 'object'>
首先我们的【菱形继承】图示如:
从左到右的分析
首先第1轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| D | D | C1,C2,C3 | C1 | 否 | 有,C1 | C1 | D,C1 |
首先第2轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| C1 | D | C2,C3 | B1 | 否 | B1还存在C2子类,删除C2(取出) | C2 | D,C1,C2 |
首先第3轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类)预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| C2 | D | C3 | B1 | 否 | 否,B1除了(C1,C2没其他子类咯) | B1 | D,C1,C2,B1 |
PS:
预查询父类是否是object 预查询父类是否还有子类,且同时又是最底层查找类的父类 ==> 都是 否的情况下,则把预查询父类作为的取出的类 首先第4轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类)预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| B1 | D | C3 | A1 | 否 | 否,A1没有子类 | A1 | D,C1,C2,B1,A1 |
PS:
预查询父类是否是object 预查询父类是否还有子类,且同时又是最底层查找类的父类 ==> 都是 否的情况下,则把预查询父类作为的取出的类
首先第5轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| A1 | D | C3 | object | 是,但底层D还有父类C3没有删除,(没有取出的子类), | 否,object没有子类 | C3 | D,C1,C2,B1,A1,C3 |
首先第6轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| C3 | D | 无 | B2 | 否 | 否,B2,无子类了(C3已经取出) | B2 | D,C1,C2,B1,A1,C3 |
PS:
预查询父类是否是object 预查询父类是否还有子类,且同时又是最底层查找类的父类 ==> 都是 否的情况下,则把预查询父类作为的取出的类
首先第7轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| B2 | D | 无 | A2 | 否 | 有,B3 | B3 | D,C1,C2,B1,A1,C3,B2 |
首先第8轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| B3 | D | 无 | A2 | 否 | 否 | A2 | D,C1,C2,B1,A1,C3,B2,A2 |
PS:
预查询父类是否是object 预查询父类是否还有子类,且同时又是最底层查找类的父类 ==> 都是 否 的情况下,则把预查询父类作为的取出的类
首先第9轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| A2 | D | 无 | object | 是(最底层D已经没有父类未取出了) | 是,A3 | A3 | D,C1,C2,B1,A1,C3,B2,A2,A3 |
PS:
预查询父类是否是object 预查询父类是否还有子类,且同时又是最底层查找类的父类 ==> 都是 是 的情况下,则把 预查询父类类剩余的子类作为取出的类
首先第10轮:
| 当前类 | 最底层查找类 | 底层未查询的父类列表 | (当前类父类) 预查询父类 | 预查询父类是否是object | 预查询父类是否还有子类,且同时又是最底层查找类的父类 | 取出当前类/剩余子类,加入连表中类(下一轮的当前类) | 当前MRO链表 |
|---|---|---|---|---|---|---|---|
| A3 | D | 无 | object | 是 | 无 | object | D,C1,C2,B1,A1,C3,B2,A2,A3,object |
https://blog.csdn.net/u011467553/article/details/81437780
原文作者:程序员小钟同学;如有侵权,请联系管理员删除。