在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算法的更多相关文章

  1. Python新式类继承的C3算法

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

  2. Python多继承的C3算法

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

  3. Python之从继承到C3算法

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

  4. python3中的新式类mro查看和C3算法原理

    两个公式 L(object) = [object] L(子类(父类1, 父类2)) = [子类] + merge(L(父类1), L(父类2) , [父类1, 父类2])注意 + 代表合并列表 mer ...

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

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

  6. 关于Python类的多继承中的__mro__属性使用的C3算法以及继承顺序解释

    刚刚学到类的多继承这个环节,当子类继承多个父类时,调用的父类中的方法具体是哪一个我们无从得知,为此,在Python中有函数__mro__来表示方法解析顺序. 当前Python3.x的类多重继承算法用的 ...

  7. python摸爬滚打之day20--多继承,MRO和C3算法

    1.新式类和经典类 在python2.2之前, 基类如果不写(), 则表示为经典类; 在python2.2之后, 经典类不复存在, 只存在新式类. 如果基类谁都不继承的话, 则默认继承object. ...

  8. python中多继承C3算法研究

    在python的面向对象继承问题中,单继承简单易懂,全部接受传承类的属性,并可添加自带属性, 但是,在多继承情况下,会遇到多个被继承者的顺序问题,以及多次继承后查找前几次继承者需求属性时,可能不易发现 ...

  9. python学习 day20 (3月27日)----(单继承多继承c3算法)

    继承: 提高代码的重用性,减少了代码的冗余 这两个写法是一样的 Wa('青蛙').walk() #青蛙 can walk wa = Wa('青蛙') wa.walk() #青蛙 can walk 1. ...

随机推荐

  1. MySQL server has gone away 的两个最常见的可能性

    [背景] 今天测试同学反馈他们docker中的测试库时不时就就报“MySQL server has gone away”,事态之紧急搞的我都有点怕了(像我这么成熟稳重 的DBA怎么有可能怕呢): 第一 ...

  2. 【MySQL (六) | 详细分析MySQL事务日志redo log】

    Reference:  https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html 引言 为了最大程度避免数据写入时 IO ...

  3. 6. 从Encoder-Decoder(Seq2Seq)理解Attention的本质

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  4. ffmpeg转码器移植VC的project:ffmpeg for MFC

    本文介绍一个自己做的FFMPEG移植到VC下的开源project:ffmpeg for MFC.本project将ffmpegproject中的ffmpeg转码器(ffmpeg.c)移植到了VC环境下 ...

  5. C++实现景区信息管理系统

    景区信息管理系统 实现了: 1.1 建立主程序应用菜单选项 主程序应用菜单选项包含所实现的所有功能,并且对选项采用数字标识进行选择,对其他错误输入可以进行判别,提示输入错误. 1.2 导游线路图的创建 ...

  6. Ubuntu16.04下搭建Go语言环境

    1. 安装GO sudo apt-get install golang-go 2. 设置Go环境变量 打开终端,输入命令: export GOROOT=$HOME/goexport PATH=$GOR ...

  7. /usr/bin/uwsgi --http :8888 --wsgi-file wsgi.py --master --processes 4 --threads 2

    /usr/bin/uwsgi --http :8888 --wsgi-file wsgi.py --master --processes 4 --threads 2 root 18756 0.0 0. ...

  8. Win2008R2+Apache+PHP+Tomcat配置

    一.VC运行库 对于Apache和PHP,在Windows上运行的话都需要对应VC运行库的支持,即Apache.PHP和VC运行库这三者的版本必须相对应,这就会带来很多问题,比如下了较新的Apache ...

  9. K8s(7)-安装Web UI

    仪表板是基于Web的Kubernetes用户界面.您可以使用仪表板将容器化应用程序部署到Kubernetes集群,对容器化应用程序进行故障排除,以及管理集群资源.您可以使用仪表板来概述群集上运行的应用 ...

  10. monit检测语法

    1.存在性检测 功能:检测文件或者服务不存在时进行相应的动作,默认是重启 语法: IF [DOES] NOT EXIST [[<X>] <Y> CYCLES]    THEN ...