转 -- Python: 多继承模式下 MRO(Method Resolution Order) 的计算方式关乎super
大家可能已经知道了,在 Python 3(Python 2 的新式类)中多继承模式是使用 C3 算法来确定 MRO(Method Resolution Order) 的。
那么具体是怎么计算的呢?本文将基于 https://www.python.org/downlo... 中的几个例子来讲解 MRO 是怎么计算的。
我们首先来定义一些符号: :
用 CN 表示一个类:C1, C2, C3, ..., CN
C1 C2 C3 ... CN 表示的是一个包含多个类的列表 [C1, C2, C3, ..., CN]
其中: :
head = C1
tail = C2 ... CN
加法运算: :
C + (C1 C2 ... CN) = C C1 C2 ... CN
[C] + [C1, C2, ... ,CN] = [C, C1, C2, ..., CN]
L[C] 表示类 C 的线性值,其实就是 C 的 MRO, 其中 :
L[object] = object
比如有个类 : :
class C(B1, B2, ..., BN): pass
那么: :
L[C(B1 ... BN)] = C + merge(L[B1] ... L[BN], B1 ... BN)
merge 的计算规则如下:
take the head of the first list, i.e L[B1][0]; if this head is not in the tail of any of the other lists, then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. Then repeat the operation until all the class are removed or it is impossible to find good heads. In this case, it is impossible to construct the merge, Python 2.3 will refuse to create the class C and will raise an exception.
计算 MRO
先从简单的类说起: :
class B(object): pass
L[B] = L[B(object)]
= B + merge(L[object])
= B + L[object]
= B object
B.mro()
[<class 'main.B'>, <type 'object'>]
简单的子类: :
class C(B): pass
L[C] = L[C(B)]
= C + merge(L[B])
= C + L[B]
= C B object # 从上面已经知道了 L[B] = B object
C.mro()
[<class 'main.C'>, <class 'main.B'>, <type 'object'>]
下面来看一个复杂的例子: :
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class C(D,F): pass
class B(D,E): pass
class A(B,C): pass
很容易就可以想到: :
L[O] = O = object
L[F] = L[F(O)] = F O
L[E] = L[E(O)] = E O
L[D] = L[D(O)] = D O
下面来计算 C, B, A:
L[C]: :
L[C] = L[C(D, F)]
= C + merge(L[D], L[F], DF)
# 从前面可知 L[D] 和 L[F] 的结果
= C + merge(DO, FO, DF)
# 因为 D 是顺序第一个并且在几个包含 D 的 list 中是 head,
# 所以这一次取 D 同时从列表中删除 D
= C + D + merge(O, FO, F)
# 因为 O 虽然是顺序第一个但在其他 list (FO)中不是 head, 跳过,
# 改为检查第二个list FO # F 是第二个 list 和其他 list 的 head,
# 取 F同时从列表中删除 F
= C + D + F + merge(O)
= C D F O
C.mro()
[<class 'main.C'>, <class 'main.D'>, <class 'main.F'>, <type 'object'>]
L[B]: :
L[B] = L[B(D, E)]
= B + merge(L[D], L[E], DE)
= B + merge(DO, EO, DE)
= B + D + merge(O, EO, E)
= B + D + E + merge(O)
= B D E O
B.mro()
[<class 'main.B'>, <class 'main.D'>, <class 'main.E'>, <type 'object'>]
L[A]: :
L[A] = L[A(B, C)]
= A + merge(L(B), L(C), BC)
= A + merge(BDEO, CDFO, BC)
= A + B + merge(DEO, CDFO, C)
# 注意这里是 C , 因为第一个list 的 head D 不是其他list 的 head
# 所以改为从下一个 list CDFO 开始
= A + B + C + merge(DEO, DFO)
= A + B + C + D + merge(EO, FO)
= A + B + C + D + E + merge(O, FO)
= A + B + C + D + E + F + merge(O)
= A B C D E F O
A.mro()
[<class 'main.A'>, <class 'main.B'>, <class 'main.C'>,
<class 'main.D'>, <class 'main.E'>, <class 'main.F'>, <type 'object'>]
到这里应该已经有一点眉目了。下面再来个上面那些类的变种,可以先自己算算看,后面有详细的计算过程。
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class C(D,F): pass
class B(E,D): pass
class A(B,C): pass
跟之前唯一的区别是 B(D, E) 变成了 B(E, D) :
L[O] = O = object
L[F(O)] = F O
L[E(O)] = E O
L[D(O)] = D O
L[C] = L[C(D, F)]
= C + merge(L[D], L[F], DF)
= C D F O
L[B] = L[B(E, D)]
= B + merge(L[E], L[D], ED)
= B + merge(EO, DO, ED)
= B + E + merge(O, DO, D)
= B + E + D + merge(O)
= B E D O
B.mro()
[<class 'main.B'>, <class 'main.E'>, <class 'main.D'>, <type 'object'>]
L[A] = L[A(B, C)]
= A + merge(L[B], L[C], BC)
= A + merge(BEDO, CDFO, BC)
= A + B + merge(EDO, CDFO, C)
= A + B + E + merge(DO, CDFO, C)
= A + B + E + C + merge(DO, DFO)
= A + B + E + C + D + merge(O, FO)
= A + B + E + C + D + F + merge(O)
= A B E C D F O
A.mro()
[<class 'main.A'>, <class 'main.B'>, <class 'main.E'>,
<class 'main.C'>, <class 'main.D'>, <class 'main.F'>, <type 'object'>]
通过这几个例子应该对如何计算 MRO 已经有所了解了,更详细的信息可以阅读 python MRO 文档 以及 wikipedia 中的 C3 算法.
转 -- Python: 多继承模式下 MRO(Method Resolution Order) 的计算方式关乎super的更多相关文章
- CodeChef - MRO Method Resolution Order(打表)
题意:有一种关系叫继承,那么继承父类的同时也会继承他的一个函数f,能继承任意多个父类或不继承,但不能继承自己的子类.现在规定一个列表,这个列表必须以1~N的顺序排列,并且父类不会排在子类后面,1含有一 ...
- Python进阶-继承中的MRO与super
Python进阶-继承中的MRO与super 写在前面 如非特别说明,下文均基于Python3 摘要 本文讲述Python继承关系中如何通过super()调用"父类"方法,supe ...
- python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法>
MRO了解: 对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置.而搜索的顺序就是所谓的「方法解析顺序」(M ...
- 【转】python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法>
[转]python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法> MRO了解: 对于支持继承的编程语言来说,其方法(属性)可能定义 ...
- Method Resolution Order – Python类的方法解析顺序
在支持多重继承的编程语言中,查找方法具体来自那个类时的基类搜索顺序通常被称为方法解析顺序(Method Resolution Order),简称MRO.(Python中查找其它属性也遵循同一规则.)对 ...
- python在交互模式下直接输入对象后回车,调用的是对象的__repr__()方法,这个方法表示的是一个编码,用print+对象是调用对象的__str__方法
交互模式下调用对象的__repr__()方法,这个方法表示的是一个编码 >>> u"国庆节快乐"u'\u56fd\u5e86\u8282\u5feb\u4e50' ...
- Release模式下无法调试打印对象的解决方式
之前碰到在release模式下无法打印对象的问题,只能切换到debug模式下调试, xcode release 模式下, 会关掉断点读取变量的上下文环境,以提高运行速度, ⚠️ 记得调试完再改回去,防 ...
- 记一下python的method resolution order(MRO)机制
一直用python都是拿着cookbook和库的文档直接撸,很少会把细节过得那么彻底,遇到问题才会翻文档. 今天看到这个例子的时候我突然触及了我的盲区,我不确定这样的继承层级调用super.foo() ...
- Python多继承的C3算法
C3算法 一.知识点补充: 拓扑排序:在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且 ...
随机推荐
- webpack4.x相关笔记整理
概念 Webpack是一个模块打包机,它可以将我们项目中的所有js.图片.css等资源,根据其入口文件的依赖关系,打包成一个能被浏览器识别的js文件.能够帮助前端开发将打包的过程更智能化和自动化. W ...
- adminlte前端框架从入门到精通
第一 下载 admintle的下载地址为: https://github.com/almasaeed2010/AdminLTE/releases 参考实例文件代码: 例如:AdminLTE-2.4.3 ...
- zabbix2.2 - FromDual.MySQL.check" became not supported
升级zabbix后发现zabbix server日志中多个实例报错如下: 27974:20171227:113001.724 item "实例name:FromDual.MySQL.chec ...
- git worktree 是什么及其使用场景
先上总结: 在git worktree出现之前, git切换分支前后的文件都只存在在当前文件夹下, git worktree出现之后, 我们可以将分支切换到其他文件夹下 比如如果你的项目有很多个版本分 ...
- python----特殊闭包
1.闭包的定义: 当子函数有调用父级函数变量(非全局变量)并返回子函数名时父级函数不会随着函数运行而结束释放,而是会保存状态等待子函数的调用. 我们常见的闭包类型: def fun1(): x = 1 ...
- BZOJ3175[Tjoi2013]攻击装置——二分图最大独立集
题目描述 给定一个01矩阵,其中你可以在0的位置放置攻击装置.每一个攻击装置(x,y)都可以按照“日”字攻击其周围的 8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y- ...
- BZOJ4516 SDOI2016生成魔咒(后缀数组+平衡树)
一个字符串本质不同的子串数量显然是总子串数减去所有height值.如果一个个往里加字符的话,每次都会改动所有后缀完全没法做.但发现如果从后往前加的话,每次只会添加一个后缀.于是我们把字符串倒过来,每次 ...
- 关于js特效轮播图练习
[出现问题] js轮播图,图片未正常轮播. [解决方法] 通过对代码的检查,发现是以下三个原因造成的错误. 1.js代码问题 js代码使用alert(test);,测试修改完毕后,发现依然没有解决错误 ...
- day9 集合操作
去重 s = set(python_1) # 用set会变成集合,集合自带去重能力 print(s) python_1 = list(s) # 在用list还原成列表.但是会打乱顺序 print(py ...
- MT【242】图像几何意义
设函数$f(x)=x^2+ax+b$,已知函数$f(x)$在$[-1,1]$上存在零点,若$0\le b-2a\le 1$,求$b$的范围 (2015浙江文科高考20(2)) 分析:理解成$g(x)= ...