Python新式类继承的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高级编程》中是如此定义的:

取第一个列表的头,也就是L[B,object] ,如果这个头不在任何表的尾部,那么将它加到ClassD的线性化中,并且从合并中的列表里删除 ;否则查找下一个列表的头,如果是个好的表头则取出它。 需要注意的是: 表头指是第一个元素 ,尾部是指除表头之外的其它所有元素 。如[A,B,C,D,E,F],A是表头,[B,C,D,E,F]是尾部。

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‘>]
时间: 2024-10-29 15:07:27

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

python的继承,多继承,经典类的MRO,新式类的MRO,C3算法,super

#继承 class JiaoFu: def qd(self): print("教父带你祈祷") class Fu: def msj(self): print("alex喜欢msj") class Zi(Fu, JiaoFu): def dbj(self): print("刘伟喜欢大宝剑") z = Zi() z.msj() z.dbj() z.qd() class Base1: # Base1 object def func(self): pri

python D20 多继承、C3算法、super()

# 今日大纲# 1.多继承# 继承:x是一种y的时候,可以使用继承关系."is a"# 一个类同时继承多个类(python, c++)# eg:孙悟空是猴子,还是神仙,还是妖怪 # 2.经典类的MRO# 通过树形结构的深度优先遍历# 一条道走到黑(从左往右) # 3.新式类的MRO(重点.面试题)c3算法# 先拆分# 在合并,第一项的头和后面所有项的身子(除了头以外的部分)进行比较,如果都没有就拿出来,如果出现了,就跳过到后一项,后一项查一个完在跳会原来的位置继续上述动作 # 4.su

经典类和新式类的区别,c3算法

一  经典类和新式类的区别 1, 只有py2中有经典类, 2.2版本以后新增了新式类.  怎样区分,新式类后面必须继承object py3 中只有新式类.写不写继承,都是默认继承object 2,  查找顺序不一样, 经典类-深度优先,就是一条道走到黑 新式类 -广度优先(这样说不太精准),通过c3算法,找出顺序 二,c3 算法 class A(object): pass class B(A): pass class C(B): pass class D(object): pass class

python中的MRO和C3算法

一. 经典类和新式类 1.python多继承 在继承关系中,python子类自动用友父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类 2.python2和python3的区别 python2中存在两种类,一个叫经典类,在python2.2之前,一直使用的经典类.经典类是在基类的根如果什么都不写.表示继承xxx 另一个叫做心事类,在python2.2之后出现了心事类.新式类的特点是基类的根是object python3中使用的都是新式类.如果基类谁都不继承,那这个

Python新式类和经典类的区别

@Python新式类和经典类的区别 class ClassicClass(): pass class NewStyleClass(object): pass x1 = ClassicClass() x2 = NewStyleClass() print x1.__class__, type(x1) print x2.__class__, type(x2) 输出结果: __main__.ClassicClass <type 'instance'> <class '__main__.NewSt

python 新式类和经典类(了解)

在python2中,有新式类和经典类和经典类的区别: 新式类 继承自object或object的子类,这样的类就叫新式类. class A(object): pass print(A.__bases__) 结果: (<class 'object'>,) 经典类 没有继承object或object的子类. >>> class A: ... pass ... >>> A.__bases__ () >>> 而在python3中不再有这种区别,所有

Python新式类与经典类的区别

1.新式类与经典类 在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性:反之,即不由任意内置类型派生出的类,则称之为“经典类”. “新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”. 官方文档 https://www.python.org/doc/new

面向对象--多继承的C3算法

在python3的面向对象中,最底层的父类都默认继承Object类,所有的类都是新式类,多继承的继承顺序遵循广度优先规则,也就是C3算法. C3算法就是 计算继承顺序时,先把要计算的子类名拿出来,在加上继承的父类的继承顺序 从左往右找第一个继承的父类继承顺序,这样会出现3中情况: 1.第一位出现的父类名,并且在后面没有出现的提出来 2.第一位出现的父类在后面出现并且也都是在第一位,那也可以提出来 3.第一位出现的父类在后面出现但是不在第一位,那么我们就要找第二个继承的父类继承顺序,看他的第一位的

【Python】Python 新式类介绍

本文转载自:kaka_ace's blog 我们使用 Python 开发时, 会遇到 class A 和 class A(object) 的写法, 这在 Python2 里是有概念上和功能上的区别, 即经典类(旧式类)与新式类的区别, 英文上分别描述为 old-style(classic-style) 与 new-style. 通过搜索, 先查阅了三个资料链接: 官方文档 stackoverflow 解答 Python Types and Objects 根据 stackoverflow 答案引