Python3多重继承排序原理(C3算法)
参考:https://www.jianshu.com/p/c9a0b055947b
类C的线性化记忆为L[C]=[C1,C2,...Cn],其中C1称为L[C]的头,其余元素[C2,...Cn]称为尾。如果一个类C继承自基类B1,B2,...,B那么L[C]的计算过程为
#类object为最高父类,所有类都继承object
L[objicet]=[object]
L[C(B1,B2,...Bn)]=[C]+merge(L[B1],L[B2],[B1,B2,...Bn])
merge是将一组列表输出为一个列表,其过程为
1,检查第一个列表的头元素,记做H
2,如果H是后续序列的第一个元素,或者不在后续序列中再次出现,则将其输出,并将其从所有列表中删除,如果不符合跳过此元素,查找下一个列表的第一个元素,然后回到步骤1
3,重复上述步骤,直至列表为空或者不能再找出可以输出的元素。
举例说明
>>> class A(object):
... pass
...
>>> class B(object):
... pass
...
>>> class C(A,B):
... pass
首先object,A,B的线性化结果比较简单
L[object]=[object]
L[A]=[A,object]
L[B]=[B,object]
python内置变量__mro__存储了
>>> object.__mro__
(<class 'object'>,)
>>> A.__mro__
(<class '__main__.A'>, <class 'object'>)
>>> B.__mro__
(<class '__main__.B'>, <class 'object'>)
需要计算出L[C]
L[C]=[C]+merge(L[A],L[B],[A,B])
=[C]+mergr([A,object],[B,object],[A,B])
#取得的第一个元素是A,是序列[A,B]的第一个元素所以输出A并且将A从所有列表中删除
=[C,A]+merge([object],[B,object],[B])
#取得的元素为object不满足条件,object是序列[B,object]的最后一个元素,跳过取到元素为B,满足条件,将B输出并从所有列表删除B
=[C,A,B]+merge([object],[object])
#最后的结果
=[C,A,B,object]
使用__mro__验证计算结果正确
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
一个复杂的例子
class B(object): pass class C(object): pass class D(A,C): pass class E(B,C): pass class F(D,E): pass
计算过程
L[F] = [F] + merge(L[D], L[E], [D, E])
= [F] + merge([D, A, C, object], [E, B, C, object], [D, E])
= [F, D] + merge([A, C, object], [E, B, C, object], [E])
= [F, D, A] + merge([C, object], [E, B, C, object], [E])
= [F, D, A, E] + merge([C, object], [B, C, object])
= [F, D, A, E, B] + merge([C, object], [C, object])
= [F, D, A, E, B, C, object]
验证计算结果
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
以上算法虽然可以计算出继承顺序,但是不直观 ,可以使用图示拓扑顺序进行推导
什么是拓扑顺序
在图论中,拓扑顺序(Topological Storting)是一个有向无环图(DAG,Directed Acyclic Graph)的所有定点的线性序列。且该序列必须满足一下两个条件
1,每个顶点出现且只出现一次
2,若存在一条从顶点A到顶点B的路径,那么在序列中顶点A出现在顶点B的前面
看下图
它是一个DAG图,那么如果写出它的拓扑顺序呢?一种比较常见的方法
1,从DAG途中选择一个没有前驱(即入度为0)的顶点并输出
2,从图中删除该顶点和所有以它为起点的有向边
3,重复1和2直到当前DAG图为空或者当前途中不存在无前驱的顶点为止。
于是得到拓扑排序后的结果为{1,2,4,3,5}
看实例
class A(object):
pass class B(object):
pass class C1(A,B):
pass class C2(A,B):
pass class D(C1,C2):
pass
根据上述继承关系构成一张图
1,找到入度为0的点,只有一个D,把D拿出来,把D相关的边减掉
2,现在有两个入度为0的点(C1,C2),取最左原则,拿C1,减掉C1相关的边,这时候的排序是{D,C1}
3, 现在入度为0的点(C2),拿掉C2,减掉C2相关的边,这时候的排序是{D,C1,C2}
4,现在入度为0的点(A,B),取最左原则,拿掉A,减掉A相关的边,这时候的排序是{D,C1,C2,A}
5,现在入度为0的点只有B,拿掉B,减掉B相关的边,最后只剩下object
所以最后的排序是{D,C1,C2,A,B,object}
验证一下结果
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.C1'>, <class '__main__.C2'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
为了进一步属性,在看一个例子
class A(object):
pass class B(object):
pass class C1(A):
pass class C2(B):
pass class D(C1,C2):
pass
继承图
1,找到入度为0的顶点,只有一个D,拿D,剪掉D相关的边
2,得到两个入度为0的顶点(C1,C2),根据最左原则,拿C1,剪掉C1相关的边,这时候序列为{D,C1}
3,接着看,入度为0的顶点有两个(A,C1),根据最左原则,拿A,剪掉A相关的边,这时候序列为{D,C1,A}
4,接着看,入度为0的顶点为C2,拿C2,剪掉C2相关的边,这时候序列为{D,C1,A,C2}
5,继续,入度为0的顶点为B,拿B,剪掉B相关的边,最后还有一个object
所以最后的序列为{D,C1,A,C2,B,object}
(<class '__main__.D'>, <class '__main__.C1'>, <class '__main__.A'>, <class '__main__.C2'>, <class '__main__.B'>, <class 'object'>)
使用图示拓扑法可以快速计算出继承顺序
Python3多重继承排序原理(C3算法)的更多相关文章
- Python多继承C3算法
Python3 多继承的MRO算法选择.MRO(Method Resolution Order):方法解析顺序. Python3 只保留了C3算法! C3算法解析: 1.C3算法解析 C3算法:MRO ...
- python多重继承C3算法
python多重继承的MRO算法选择: 经典方式.Python2.2 新式算法.Python2.3 新式算法(C3).Python 3中只保留了最后一种,即C3算法 C3算法的解析: 1.多继承UML ...
- python3的C3算法
一.基本概念 1. mro序列 MRO是一个有序列表L,在类被创建时就计算出来. 通用计算公式为: mro(Child(Base1,Base2)) = [ Child ] + merge( mro(B ...
- 转载 python多重继承C3算法
备注:O==object 2.python-C3算法解析: #C3 定义引用开始 C3 算法:MRO是一个有序列表L,在类被创建时就计算出来. L(Child(Base1,Base2)) = [ Ch ...
- 关于Python类的多继承中的__mro__属性使用的C3算法以及继承顺序解释
刚刚学到类的多继承这个环节,当子类继承多个父类时,调用的父类中的方法具体是哪一个我们无从得知,为此,在Python中有函数__mro__来表示方法解析顺序. 当前Python3.x的类多重继承算法用的 ...
- MySQL排序原理与案例分析
前言 排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Group by语句,Distinct ...
- 【MySQL】排序原理与案例分析
前言 排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Group by语句,Distinct语句都会隐 ...
- MySQL排序原理与MySQL5.6案例分析【转】
本文来自:http://www.cnblogs.com/cchust/p/5304594.html,其中对于自己觉得是重点的加了标记,方便自己查阅.更多详细的说明可以看沃趣科技的文章说明. 前言 ...
- [转]MySQL排序原理与案例分析
这篇文章非常好,就把他转过来 前言 排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Grou ...
随机推荐
- Mybatis配置文件中#{ }和${ }的区别
#{ }和${ }都可以从map中取到相对应的值, 但是 #{ }采取的是预编译的方式(PreparedStatement)来执行sql语句,有效防止了sql注入问题 select * from bo ...
- jq导航
做外部前端都会用到导航栏应用 一般导航应用会鼠标碰到变颜色 或子导航出现 下面为基本的导航 <div class="header"> <ul style=&qu ...
- 第三章 基本的bash shell命令
1.硬链接:等同于引用了原文件,并未产生新的文件,不同的硬链接共用一个inode 2.符号链接:创建的是一个新文件,新文件指向原文件,因为是不同的文件,所以有不同的inode
- [Luogu] 受欢迎的牛
https://www.luogu.org/problemnew/show/P2341 Tarjan 缩点 + 判断出度 #include <iostream> #include < ...
- BZOJ 2038: [2009国家集训队]小Z的袜子
二次联通门 : BZOJ 2038: [2009国家集训队]小Z的袜子 /* BZOJ 2038: [2009国家集训队]小Z的袜子 莫队经典题 但是我并不认为此题适合入门.. Answer = ∑ ...
- bootstrap中tab切换的使用
文档地址:https://v3.bootcss.com/javascript/#tabs 简单实例: <!DOCTYPE html> <html lang="en" ...
- IDEA构建支持cdh版本和scala的maven项目注意事项
工具和环境 idea2018.1 , scala2.11.8, scala的idea支持包,下载地址 maven3.3.9 win10系统 1.maven环境配置 下载解压maven包,(也可以使用i ...
- CF757F Team Rocket Rises Again——最短路+支配树
CF757F Team Rocket Rises Again 全体起立,全体起立,这是我A的第一道黑题(虽然是CF的): 来一波番茄攻击: 不扯淡了,这道题也是学习支配树(之前)应该做的题: 和灾难不 ...
- [CERC2015]Juice Junctions(边双连通+字符串hash)
做法 考虑边数限制的特殊条件,显然答案仅有\(\{0,1,2,3\}\) 0:不联通 1:连通 2:边双连通 3:任意删掉一条边都为边双连通 考虑每次删边后记录各点的边双染色情况来特判\(3\):是否 ...
- python3编程基础之一:代码封装
几乎现代的编程语言都支持函数,函数是代码段的封装,并能实现一特定功能,并能重复使用的代码单位.之前的pow()和sqrt()和print()和input()等类似的内置函数,就是python内部已经实 ...