python多继承顺序_Python多重继承方法解析顺序(MRO构建算法)
分界
python的MRO算法有新旧两种,但并不是以python2和python3为界,具体的分隔为:在python2中如果定义类的时候没有指定父类是object,即定义为
class A:
pass
的使用旧算法。如果指定父类为object的:
class A(object):
pass
使用新算法,python3都是用新算法。
旧算法
先看示例,类图:
python_a.png
代码:
class A:
def who_am_i(self):
print("I am a A")
class B(A):
def who_am_i(self):
print("I am a B")
class C(A):
def who_am_i(self):
print("I am a C")
class D(B,C):
def who_am_i(self):
print("I am a D")
d1 = D()
d1.who_am_i()
毫无疑问这段代码会输出“I am a D”,稍微改一下D的定义:
class D(B,C):
pass
这时候找到了B实现的方法所以打印出“I am a B”,如果我们把B的实现也去掉:
class B(A):
pass
奇怪的事情发生了,输出是“I am a A”,因为旧算法的MRO推导算法很直观,它使用树状结构组织类。当函数调来到来的时候从左往右的使用深度优先遍历父类:
1,检查对象是否实现了方法
2,如果没有找到,检查首个父类是否实现了该方法
3,如果没有找到,检查本类是否还继承了其他类,是的话从其他分支向上追溯
所以对于本例,查找的顺序就是D B A C A,最后一个A不重复加入最终的顺序是D B C A
来一个例子检查:
class A1():
# def who_am_i(self):
# print("I am a A1")
pass
class A2():
def who_am_i(self):
print("I am a A2")
class A3():
def who_am_i(self):
print("I am a A3")
class B(A1, A2):
# def who_am_i(self):
# print("I am a B")
pass
class C(A3):
def who_am_i(self):
print("I am a C")
class D(B,C):
# def who_am_i(self):
# print("I am a D")
pass
d1 = D()
d1.who_am_i()
类图为:
python2_mro.png
套用刚才的规则,查找方法的顺序应该是D B A1 A2 C A3,所以上述代码在python2上的输出是“I am a A2”
新算法
仍然以第一段代码作为例子,重新贴一下类图
python_a.png
新算法在构建MRO的时候第一步与旧算法一样,所以初步结果是D B A C A,然后从左到右判断每个元素是否为“好头(good head)”,不是的话从链中去掉。“好头(good head)”的定义是 - 从该元素开始到链尾,不存在任何元素是该元素的子类 - 初步结果的D, B没问题,第一个A不是好头因为C是其子类所以去掉,再往后的C A也没问题了,最终结果是D B C A,所以在python 3以及当A继承于object的时候如果D,B都不实现who_am_i则最终输出的是“I am a C”。
不可构建的MRO - 新算法补充
考虑如下蛋疼的继承结构:
Use case.png
代码:
class X():
def who_am_i(self):
print("I am a X")
class Y():
def who_am_i(self):
print("I am a Y")
class A(X, Y):
def who_am_i(self):
print("I am a A")
class B(Y, X):
def who_am_i(self):
print("I am a B")
class F (A, B):
def who_am_i(self):
print("I am a F")
f = F()
f.who_am_i()
如果使用“新算法”,按照上述章节的分析,构建出来的MRO结果应该是F A B Y X,使用python 3跑一遍,结果得到输出:
Traceback (most recent call last):
File "bad_mro.py", line 26, in
class F(A, B):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases X, Y
这又是啥毛病呢,实际上新算法用的是线性算法记为L[]运算以及merge()操作来构造MRO,改线性算法描述为:类C的线性结果是C与merge(C的所有父类的线性结果)之和,用表达式表示为:
L[C(B1...Bn)] = C + merge(L[B1]...L[Bn], B1...Bn)
上边例子的表达式就是:
L[F(A, B)] = F + merge(L[A], L[B], A, B)
merge()运算的规则是:
1,取出merge()中第一个list的第一个元素作为head
2,如果这个head不出现在其他list的尾部,则它是一个“好头”,可以从merge()中移出来
3,否则,取出下一个list中的第一个元素作同样的判断
4,重复上述过程直至所有的类都移到merge()算子的外部则构建MRO完成
5,否则,改继承结果无法生成MRO
所以对于L[F(A, B)] = F + merge(L[A], L[B], A, B)这个表达式,L[A], L[B]可以先按照L[]算法展开为:
L[A]=L[A(X, Y)]=A+merge(L[X],L[Y],X,Y)=A+merge(X,Y,X,Y)=A,X,Y
L[B]=L[B(Y, X)]=B+merge(L[Y],L[X],Y,X)=B+merge(Y,X,Y,X)=B,Y,X
例如这里的merge(X,Y,X,Y)首先判断X,因为X不在其他list的尾部(X算是list的头部)所以先提取X出来,这时候变成了A,X+merge(Y,Y)显然Y也能直接提取出来了;merge(Y,X,Y,X)同理。
把这俩结果代回去,总式子为:
L[F(A,B)] = F + merge( (A,X,Y), (B, Y, X), A, B)
这时候先判断A,因为不在其他list的尾部,所以提出出来式子变为:
F,A + merge((X, Y), (B, Y, X), B)
再判断第二个list的第一个元素B,也不在其他list的尾部,所以提出来:
F,A,B + merge((X, Y), (Y, X))
接着第二轮判断第一个list的头元素X,结果在第二个list中发现了X在尾部不能提取;再判断Y*结果发现在第一个list的尾部也不行。所以最终就遇到了不可构建MRO的情况!
结论
可见,虽然python的多重继承非常强大但是必须小心注意继承顺序(避免上述章节中提及的MRO不可构建的继承结构),与Java这种单继承语言不同 - super()总是沿着继承链向上追溯。python中方法的super()并不总是指向其声明的父类的同名方法,而是沿着MRO从左到往的传播。
python多继承顺序_Python多重继承方法解析顺序(MRO构建算法)相关推荐
- python类中方法的执行顺序-python – 新式类中的方法解析顺序(MRO)?
在Python in a Nutshell(第2版)一书中有一个使用的例子 旧样式类,用于演示如何以经典分辨率顺序解析方法 它与新订单有何不同. 我通过重写新样式的示例尝试了相同的示例,但结果与使用旧 ...
- python类中方法的执行顺序-浅谈Python的方法解析顺序(MRO)
方法解析顺序, Method Resolution Order 从一段代码开始 考虑下面的情况: class A(object): def foo(self): print('A.foo()') cl ...
- python方法解析顺序_浅谈Python的方法解析顺序(MRO)
方法解析顺序, Method Resolution Order 从一段代码开始 考虑下面的情况: class A(object): def foo(self): print('A.foo()') cl ...
- python新式类c3算法_Python新式类的方法解析顺序MRO与Super
新式类与经典类的方法解析顺序 MOR(方法解析顺序) 经典类:深度优先 DFS python3以前 新式类:广度优先 python2.2 新式类:广度优先的C3算法实现(拓扑排序) BFS pytho ...
- 图解Python 3.x多继承时方法解析顺序MRO
在Python 3.x的多继承树中,如果在中间层某类有向上一层解析的迹象,则会先把本层右侧的其他类方法解析完,然后从本层最后一个解析的类方法中直接进入上一层并继续解析,也就是在从子类到超类的反向树中按 ...
- python面向对象--方法解析顺序(MRO)
转载:https://www.cnblogs.com/qunxiadexiaoxiangjiao/p/8311429.html 对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于 ...
- Python的方法解析顺序(MRO)变化过程
MRO,即 Method Resolution Order,是继承中确定调用哪个方法(属性)的搜索顺序方法. 对于只支持单继承的语言(Java和C#)来说,MRO 一般比较简单:而对于 C++, Py ...
- mro python_Python新式类的方法解析顺序MRO与Super
新式类与经典类的方法解析顺序 MOR(方法解析顺序) 经典类:深度优先 DFS python3以前 新式类:广度优先 python2.2 新式类:广度优先的C3算法实现(拓扑排序) BFS pytho ...
- Python3的方法解析顺序(MRO)
Python 2.3 的新式类的 C3 算法.它也是 Python 3 唯一支持的方式(笔者使用python3,所以就先讲这种的) 一个例子: class D(object): pass class ...
最新文章
- 操作系统学习:Linux0.12文件异步IO
- 后处理程序文件大小的变量_【每日一题】(17题)面试官问:JS中事件流,事件处理程序,事件对象的理解?...
- js不停地触发按钮的事件
- matlab regress()
- [Oracle] oracle统计信息
- [JavaWeb-JavaScript]JavaScript注释数据类型
- QS首发大学百强排名,华东五校表现惊艳,老牌985望尘莫及
- word2vec数学原理详解
- 理正深基坑弹性计算方法_理正深基坑整体计算与单元计算的区别
- python地理数据处理环境搭建
- 高分影像批处理第一回——数据格式分析与整理
- 广告联盟反作弊一些常识
- 埃森哲互动成为全球最大的数字营销服务商
- 程序猿的一些幽默趣闻 个个经典
- 群辉安装python3,pip,环境变量配置
- 利用阿里云搭建NFS服务器
- html鼹鼠游戏,疯狂鼹鼠
- Golang知识点二、GMP调度模型
- Nacos服务注册与发现源码(一)之gRPC协议的实例注册
- 电子邮件服务器需要那两个协议,电子邮件有哪两个协议
热门文章
- 某程序员哀叹:连续帮三任女朋友进360,京东等互联网大厂,进去后却都惨遭分手!...
- 因4元而市值蒸发400亿!美团“大数据杀熟”翻车!回顾2020年互联网大事件!...
- 推荐一位高性能服务开发专家!是他让我从专科,蜕变为年薪百万后端开发!...
- 从 LRU Cache 带你看面试的本质
- 分享10个实用的高效办公神器,极大地提高办公效率
- B2B2C网站系统建设的常见误区
- JSP内置对象-request
- ubuntu mysql 内存满了_ubuntu – 如何为mySQL分配内存限制?
- 西文是指什么_中西文化的关键性差别
- RFID读写器Impinj R420开发C#