Python多继承解析顺序的C3线性算法流程解析
Python多继承MRO
在Python2.1中,采用了经典类,使用深度优先算法解析。
Python2.2中,引入了新式类,使用深度优先算法和广度优先算法。
在Python2.3以后的版本中,经典类和新式类共存,使用了DFS算法和C3算法。
Python2中的经典类
class A(object):
pass
Python3的新式类
class A:
pass
C3算法
In computing, the C3 superclass linearization is an algorithm used primarily to obtain the order in which methods should be inherited (the "linearization") in the presence of multiple inheritance, and is often termed Method Resolution Order (MRO).
这是维基百科中的定义,下面这张图是一张多继承的关系图:
那么这里的mro解析顺序是如何的呢?单纯看图很难得出答案。
C3线性算法的推导过程如下:
假设类C继承自父类B1,...Bn,类C的解析列表公式如下:
这个公式表明C的解析列表是通过对其所有父类的解析列表及其父类一起merge得到的。
merge操作分为如下几个步骤:
- 选取merge中的第一个列表记为当前列表K。
- 令h = head(K), 如果h没有出现在其他任何列表的tail(列表中除了第一个元素,其余的称之为tail)当中,那么将其加入类C的线性化列表中,并将其从merge中的所有列表移除,之后重复步骤2.
- 否则,设置K为merge的下一个列表,重复2中的操作
- 如果merge的所有类都被移除,则输出类创建成功;如果不能找到下一个h,则输出C类抛出异常。
推导过程
我们用上面的那张图试一下推导出mro的解析顺序。
上面那张图转换为python代码如下:
转换成Python代码
O = object
class A(O): pass
class B(O): pass
class C(O): pass
class D(O): pass
class E(O): pass
class K1(A, B, C): pass
class K2(D, B, E): pass
class K3(D, A): pass
class Z(K1, K2, K3): pass
print(Z.mro())
推导
L(K1) = K1 + merge(L[A],L[B],L[C],(A,B,C))
= K1 + merge(L[A,O],L[B,O],L[C,O],(A,B,C))
= [K1,A] + merge(L[O],L[B,O],L[C,O],(B,C))
= [K1,A,B] + merge(L[O],L[O],L[C,O],(C))
= [K1,A,B,C] + merge(L[O],L[O],L[O])
= [K1,A,B,C,O]
L(K2) = [K2,D,B,E,O]
L(K3) = [K3,D,A,O]
以上是K1,K2,K3的解析顺序
下面是Z的推导过程
L(Z) = Z + merge(L(K1)+L(K2)+L[K3],(K1,K2,K3))
= Z + merge(L[K1,A,B,C,O]+L(K2,D,B,E,O)+L(K3,D,A,O),(K1,K2,K3))
= [Z,K1] + merge(L[A,B,C,O]+L(K2,D,B,E,O)+L(K3,D,A,O),(K2,K3))
= [Z,K1,K2] + merge(L[A,B,C,O]+L(D,B,E,O)+L(K3,D,A,O),(K3))
= [Z,K1,K2,K3] + merge(L[A,B,C,O]+L(D,B,E,O)+L(D,A,O))
= [Z,K1,K2,K3,D] + merge(L[A,B,C,O]+L(B,E,O)+L(A,O))
= [Z,K1,K2,K3,D,A] + merge(L[B,C,O]+L(B,E,O)+L(O))
= [Z,K1,K2,K3,D,A,B] + merge(L[C,O]+L(E,O)+L(O))
= [Z,K1,K2,K3,D,A,B,C] + merge(L[O]+L(E,O)+L(O))
= [Z,K1,K2,K3,D,A,B,C,E,O]
我们得出的最终答案为:Z的解析顺序:Z->K1->K2->K3->D->A->B->C->E->O
为了验证答案,我们在python中运行
print(Z.mro())
结果如下
[<class '__main__.Z'>, <class '__main__.K1'>, <class '__main__.K2'>, <class '__main__.K3'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>]
和我们推导的结果相同,这就是C3算法的流程。
Python多继承解析顺序的C3线性算法流程解析的更多相关文章
- Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析
一.一个请求来到Django 的生命周期 FBV 不讨论 CBV: 请求被代理转发到uwsgi: 开始Django的流程: 首先经过中间件process_request (session等) 然后 ...
- SSL/TLS算法流程解析
SSL/TLS 早已不是陌生的词汇,然而其原理及细则却不是太容易记住.本文将试图通过一些简单图示呈现其流程原理,希望读者有所收获. 一.相关版本 Version Source Description ...
- [MapReduce_3] MapReduce 程序运行流程解析
0. 说明 Word Count 程序运行流程解析 && MapReduce 程序运行流程解析 1. Word Count 程序运行流程解析 2. MapReduce 程序运行流程图
- sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO
sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...
- Python多继承的C3算法
C3算法 一.知识点补充: 拓扑排序:在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且 ...
- Python的方法解析顺序(MRO)[转]
本文转载自: http://hanjianwei.com/2013/07/25/python-mro/ 对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就 ...
- Method Resolution Order – Python类的方法解析顺序
在支持多重继承的编程语言中,查找方法具体来自那个类时的基类搜索顺序通常被称为方法解析顺序(Method Resolution Order),简称MRO.(Python中查找其它属性也遵循同一规则.)对 ...
- python 方法解析顺序 mro
一.概要: mor(Method Resolution Order),即方法解析顺序,是python中用于处理二义性问题的算法 二义性: 1.两个基类,A和B都定义了f()方法,c继承A和B那么C调用 ...
- Python的程序结构[2] -> 类/Class[2] -> 方法解析顺序 MRO
方法解析顺序 / MRO (Method Resolution Order) 关于方法解析顺序(MRO)的详细内容可以参考文末链接,这里主要对 MRO 进行简要的总结说明以及一些练习示例. 经典类和新 ...
随机推荐
- oo原则
基本原则: 封装变化Encapsulate what varies. 面向接口编程而非实现 Code to an interface rather than to an implementation. ...
- Openssl crl2pkcs7命令
一.简介 crl2pkcs命令用来根据CRL或证书来生成pkcs#7消息. 二.语法 openssl crl2pkcs7 [-inform PEM|DER ] [-outform PEM|DER ...
- json操作工具-LitJson
LitJSON是json生成与读取的操作工具,使用很方便并且网上还能找到源码.下面是使用LitJSON的例子: 一.生成json:实例化一个JsonData,然后按照List数组的方式向里面填. Js ...
- 查看并解除Oracle锁
当某个数据库用户在数据库中插入.更新.删除一个表的数据,或者增加一个表的主键时或者表的索引时, 常常会出现ora-00054:resource busy and acquire with nowait ...
- mount命令使用
mount命令是一个很常用的命令,这里介绍两个服务器上之间的挂载 1 配置NFS服务 FTP服务器提供NFS服务,开放具体路径(/home/hadoop)完全控制权限给其他板子.可以将两个板子之间建立 ...
- twitter集成第三方登录是窗口一直出现闪退的解决方法
需要创建自己的token,如下图
- QT学习之事件处理
Qt事件机制 Qt程序是事件驱动的, 程序的每个动作都是由幕后某个事件所触发.. Qt事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. Qt事件的类型很多, 常见的qt的事件如下: 键盘事 ...
- g++中宏NULL究竟是什么?
NULL是个指针,还是个整数?0?或(void*)0?答案是和g++版本有关.g++ 4.6支持C++11,引入了nullptr,也许会发生变化. 可以写段简单代码求证一下: #include < ...
- (转)@RequestParam @RequestBody @PathVariable 等参数绑定注解详解
引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后,该篇主要讲解request 数据到handler method 参数数据的绑定所用到的注解和什么情形下使用: 简介: han ...
- ZT 基于git的版本管理思路
http://nvie.com/posts/a-successful-git-branching-model/ 分为5种分支: feature:功能分支,开发人员在此种分支下开发新的功能,开发完成后m ...