类的继承和C3算法
在Python的新式类中,方法解析顺序并非是广度优先的算法,而是采用C3算法,只是在某些情况下,C3算法的结果恰巧符合广度优先算法的结果。
可以通过代码来验证下:
class NewStyleClassA(object):
var = 'New Style Class A' class NewStyleClassB(NewStyleClassA):
pass class NewStyleClassC(NewStyleClassA):
var = 'New Style Class C' class SubNewStyleClass(NewStyleClassB, NewStyleClassC):
pass if __name__ == '__main__':
print(SubNewStyleClass.mro())
print(SubNewStyleClass.var)
从第一段代码的运行结果来看,与广度优先的算法结果恰巧相同,但也只是恰巧相同,不等于就是广度优先的算法。
[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassC'>, <class '__main__.NewStyleClassA'>, <type 'object'>]
New Style Class C
通过对代码进行修改可以证实:
将NewStyleClassC改为继承自object
class NewStyleClassA(object):
var = 'New Style Class A' class NewStyleClassB(NewStyleClassA):
pass class NewStyleClassC(object):
var = 'New Style Class C' class SubNewStyleClass(NewStyleClassB, NewStyleClassC):
pass if __name__ == '__main__':
print(SubNewStyleClass.mro())
print(SubNewStyleClass.var)
运行代码输出结果
[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class '__main__.NewStyleClassC'>, <type 'object'>]
New Style Class A
从代码运行结果上看,并不符合广度优先的原则。
关于C3算法,在Python官方文档中是如此解释的:
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.
C3算法的本质就是Merge,不断地把mro()函数返回的序列进行Merge,规则如下:
1. 如果第一个序列的第一个元素,是后续序列的第一个元素,或者不再后续序列中再次出现,则将这个元素合并到最终的方法解析顺序序列中,并从当前操作的全部序列中删除。
2. 如果不符合,则跳过此元素,查找下一个列表的第一个元素,重复1的判断规则
使用第一段代码逐步进行方法解析:
1.先打印NewStyleClassB和NewStyleClassC的mro(),得到他们的继承顺序序列
[<class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class 'object'>]
[<class '__main__.NewStyleClassC'>, <class 'object'>]
2.根据C3算法逐步对继承顺序进行解析:
mro(SubNewStyleClass)
= [SubNewStyleClass] + merge(mro(NewStyleClassB), mro(NewStyleClassC), [NewStyleClassB, NewStyleClassC])
# 根据第一步的打印结果,可以得出
= [SubNewStyleClass] + merge([NewStyleClassB, NewStyleClassA, object], [NewStyleClassC, NewStyleClassA, object], [NewStyleClassB, NewStyleClassC])
# 判断merge的当前序列第一个元素 NewStyleClassB, 在第三个序列中的第一个元素也存在,所以将其合并到最终序列并且删除:
= [SubNewStyleClass, NewStyleClassB] + merge([NewStyleClassA, object], [NewStyleClassC, NewStyleClassA, object], [NewStyleClassC])
# 判断merge的当前序列第一个元素 NewStyleClassA,在第二个序列中存在,并且不为第二个序列的第一个元素,则跳过
# 继续判断第二个序列中的第一个元素 NewStyleClassC,在第三个序列中存在,并且为第一个元素,所以将其合并到最终序列并且删除:
= [SubNewStyleClass, NewStyleClassB, NewStyleClassC] + merge([NewStyleClassA, object], [NewStyleClassA, object])
# 目前第一个序列的第一个元素是NewStyleClassA,所以再次对NewStyleClassA进行判断。
# NewStyleClassA在第二个序列中存在,并且为第二个序列的第一个元素,所以将其合并到最终序列并且删除:
= [SubNewStyleClass, NewStyleClassB, NewStyleClassC, NewStyleClassA] + merge([object], [object])
# 最终object,在第二个序列中出现,并且为第一个元素,所以将其合并到最终的序列并且删除,得到最终的继承顺序:
= [SubNewStyleClass, NewStyleClassB, NewStyleClassC, NewStyleClassA, object)
解析的结果和调用SubNewStyleClass.mro()方法打印出的结果是相同的:
[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassC'>, <class '__main__.NewStyleClassA'>, <class 'object'>]
使用第二段代码逐步进行方法解析:
1. 先打印NewStyleClassB和NewStyleClassC的mro(),得到他们的继承顺序序列
[<class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class 'object'>]
[<class '__main__.NewStyleClassC'>, <class 'object'>]
2. 根据C3算法逐步对继承顺序进行解析:
mro(SubNewStyleClass)
= [SubNewStyleClass] + merge(mro(NewStyleClassB), mro(NewStyleClassC), [NewStyleClassB, NewStyleClassC])
# 根据第一步的打印结果,可以得出
= [SubNewStyleClass] + merge([NewStyleClassB, NewStyleClassA, object], [NewStyleClassC, object], [NewStyleClassB, NewStyleClassC])
# 判断merge的当前序列第一个元素 NewStyleClassB, 在第三个序列中的第一个元素也存在,所以将其合并到最终序列并且删除:
= [SubNewStyleClass, NewStyleClassB] + merge([NewStyleClassA, object], [NewStyleClassC, object], [NewStyleClassC])
# 判断merge的当前序列第一个元素 NewStyleClassA,在后续的序列中都不存在,所以将其合并到最终的序列并且删除:
= [SubNewStyleClass, NewStyleClassB, NewStyleClassA] + merge([object], [NewStyleClassC, object], [NewStyleClassC])
# 判断merge的当前序列第一个元素 object,在第二个序列中出现,并且不是第一个元素,则跳过
# 跳过object后,继续判断下个序列的第一个元素,也就是第二个序列的第一个元素NewStyleClassC,在第三个序列中出现并且为第一个元素,所以将其合并到最终的序列并且删除:
= [SubNewStyleClass, NewStyleClassB, NewStyleClassA, NewStyleClassC] + merge([object], [object])
# 再次判断object,在第二个序列中出现,并且为第一个元素,所以将其合并到最终的序列并且删除,得到最终的继承顺序:
= [SubNewStyleClass, NewStyleClassB, NewStyleClassA, NewStyleClassC, object)
和调用SubNewStyleClass.mro()方法打印出的结果是相同的
[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class '__main__.NewStyleClassC'>, <class 'object'>]
类的继承和C3算法的更多相关文章
- Python新式类继承的C3算法
在Python的新式类中,方法解析顺序并非是广度优先的算法,而是采用C3算法,只是在某些情况下,C3算法的结果恰巧符合广度优先算法的结果. 可以通过代码来验证下: class NewStyleClas ...
- Python多继承的C3算法
C3算法 一.知识点补充: 拓扑排序:在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且 ...
- Python之从继承到C3算法
在Python2.X和Python3.X有很多不同的地方,其中一个区别就是和继承有关. 在Python3.X中,一个类如果没有指明其继承哪个类的时候,其默认就是继承object类. 而在Python2 ...
- python3中的新式类mro查看和C3算法原理
两个公式 L(object) = [object] L(子类(父类1, 父类2)) = [子类] + merge(L(父类1), L(父类2) , [父类1, 父类2])注意 + 代表合并列表 mer ...
- python新式类继承------C3算法
一.引入 mro即method resolution order,主要用于在多继承时判断调的属性的路径(来自于哪个类).之前查看了很多资料,说mro是基于深度优先搜索算法的.但不完全正确在Python ...
- 关于Python类的多继承中的__mro__属性使用的C3算法以及继承顺序解释
刚刚学到类的多继承这个环节,当子类继承多个父类时,调用的父类中的方法具体是哪一个我们无从得知,为此,在Python中有函数__mro__来表示方法解析顺序. 当前Python3.x的类多重继承算法用的 ...
- python摸爬滚打之day20--多继承,MRO和C3算法
1.新式类和经典类 在python2.2之前, 基类如果不写(), 则表示为经典类; 在python2.2之后, 经典类不复存在, 只存在新式类. 如果基类谁都不继承的话, 则默认继承object. ...
- python中多继承C3算法研究
在python的面向对象继承问题中,单继承简单易懂,全部接受传承类的属性,并可添加自带属性, 但是,在多继承情况下,会遇到多个被继承者的顺序问题,以及多次继承后查找前几次继承者需求属性时,可能不易发现 ...
- python学习 day20 (3月27日)----(单继承多继承c3算法)
继承: 提高代码的重用性,减少了代码的冗余 这两个写法是一样的 Wa('青蛙').walk() #青蛙 can walk wa = Wa('青蛙') wa.walk() #青蛙 can walk 1. ...
随机推荐
- 【转载】linux系统时间自动同步:ntp
NTP基本介绍 NTP(Network TimeProtocol,网络时间协议),使用来使本地机器与服务端机器时间保持同步的一种协议.如果我们只有一台机器那么只需要安装NTP客户端ntpdate这个包 ...
- 那些好用的Chrome 插件
1. json-viewer 推荐理由:一款Chrome浏览器查看JSON数据自动格式化显示的浏览器插件 https://github.com/tulios/json-viewer
- kafka性能测试
参考阿里中间件团队博客的博文 Kafka vs RocketMQ——多Topic对性能稳定性的影响 使用的测试工具为Jmeter
- Maven私服(Repository Manager) - Nexus安装和使用(详细过程)
Maven私服的安装和使用. (注:原创文章,引用请注明来自Clement-Xu的博客!) Maven私服(即Repository Manager)的主要作用: 减少从远方仓库下载的次数,节省带宽.提 ...
- 0710 mux协议的作用(ppp拨号时如何和gprs进行at指令交互)
ppp拨号使gprs上网的同时如何和gprs模块进行at指令的交互,这是一个问题. 在linux中,ppp拨号上网是内核中支持的,只需要在内核配置中选上. ppp拨号的方式使gprs进行上网与at指令 ...
- 使用react-navigation提示undefind is not a function
在学习react-natrive的时候,看到导航跳转一章,遂试了一下demo: 但是呢,在安卓模拟器上却报错了: 找了许多方法,包括降低版本都不行,后来修改了一下导出就可以了:
- Windows 10 如何使用「系统还原」功能备份系统状态和配置
https://www.sysgeek.cn/windows-10-system-restore/ 在 Windows 10 系统中,「系统还原」功能旨在创建配置快照,并在检测到系统更改时将其工作状态 ...
- [Golang] 编译程序时打上git提交信息标记
1.加入代码 //version.go package version import ( "flag" "fmt" "os" ) var ( ...
- Vue Cli 3.x项目如何部署到IIS子站点下
Vue Router在IIS下的部署参考:https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E5%90%8E%E7%AB% ...
- STM32终端优先级,看过很多感觉这个写的直白易懂
转自野火<零死角玩转STM32> 一.抢占优先级和响应优先级 STM32 的中断向量具有两个属性,一个为抢占属性,另一个为响应属性,其属性编号 越小,表明它的优先级别越高. 抢占,是 ...