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