在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'>]

Python新式类继承的C3算法的更多相关文章

  1. python新式类继承------C3算法

    一.引入 mro即method resolution order,主要用于在多继承时判断调的属性的路径(来自于哪个类).之前查看了很多资料,说mro是基于深度优先搜索算法的.但不完全正确在Python ...

  2. Python之从继承到C3算法

    在Python2.X和Python3.X有很多不同的地方,其中一个区别就是和继承有关. 在Python3.X中,一个类如果没有指明其继承哪个类的时候,其默认就是继承object类. 而在Python2 ...

  3. python中的MRO和C3算法

    一. 经典类和新式类 1.python多继承 在继承关系中,python子类自动用友父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类 2.python2和python ...

  4. Python新式类和经典类的区别

    @Python新式类和经典类的区别 class ClassicClass(): pass class NewStyleClass(object): pass x1 = ClassicClass() x ...

  5. 类的继承和C3算法

    在Python的新式类中,方法解析顺序并非是广度优先的算法,而是采用C3算法,只是在某些情况下,C3算法的结果恰巧符合广度优先算法的结果. 可以通过代码来验证下: class NewStyleClas ...

  6. Python多继承的C3算法

    C3算法 一.知识点补充: 拓扑排序:在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且 ...

  7. Python新式类与经典类的区别

    1.新式类与经典类 在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性:反之,即不由任意内置类型派生出的类 ...

  8. Python新式类与经典类(旧式类)的区别

    看写poc的时候看到的,思考了半天,现在解决了 转载自http://blog.csdn.net/zimou5581/article/details/53053775 Python中类分两种:旧式类和新 ...

  9. python之路--MRO和C3算法

    一 . MRO(method resolution order) 多继承的一种方法,一种查找的顺序 在python3 里面是一种新类式MRO 需要用都的是C3算法 class A: pass clas ...

随机推荐

  1. javascript设计模式——迭代器模式

    前面的话 迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示.迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也 ...

  2. Springboot学习记录1--概念介绍以及环境搭建

    摘要:springboot学习记录,环境搭建: 官方文档地址:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/ht ...

  3. 【Win 10 应用开发】MIDI 音乐合成——乐理篇

    针对 MIDI 音乐的 API ,其实在 Win 8.1 的时候就出现.在UWP中采用了新的驱动模式,MIDI 消息传递更加高效. 首先得说明的是,UWP 的 MIDI 相关 API 不是针对 MID ...

  4. Create-React-App创建antd-mobile开发环境(学习中的记录)

    (参考别人结合自己的整理得出,若有错误请大神指出) Facebook 官方推出Create-React-App脚手架,基本可以零配置搭建基于webpack的React开发环境,内置了热更新等功能. 详 ...

  5. Android Things 专题6 完整的栗子:运用TensorFlow解析图像

    文| 谷歌开发技术专家 (GDE) 王玉成 (York Wang) 前面絮叨了这么多.好像还没有一个整体的概念.我们怎样写一个完整的代码呢? 如今深度学习非常火,那我们就在Android Things ...

  6. C++、Objective-C 混合编程

    在XCODE中想使用C++代码,你须要把文件的扩展名从.m改成.mm.这样才会启动g++编译器. 我们来看个測试代码: [java] view plaincopy class TestC { priv ...

  7. 【npm】如何在Atom中安装emmet和atom-beautify插件?

    为了提高编写HTML和CSS的速度,最近尝试着在Atom中安装emmet插件,下面谈谈安装成功的过程 1首先我尝试了网上教程中介绍最多的方法:打开Atom的引导界面(Welcome Guide)中的i ...

  8. ZKWeb网页框架2.0正式发布

    2.0.0更新的内容有 更新框架要求 框架要求从 netstandard 1.6 升到 netstandard 2.0 框架要求从 netcoreapp1.1 升到 netcoreapp2.0 更新引 ...

  9. Android查缺补漏(View篇)--在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0?

    在 Activity 的 onCreate() 方法中为什么获取 View 的宽和高为0 ? @Override protected void onCreate(Bundle savedInstanc ...

  10. 《Netty5.0架构剖析和源码解读》【PDF】下载

    <Netty5.0架构剖析和源码解读>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062545 内容简介 Netty 是个异步的 ...