码迷,mamicode.com
首页 > 编程语言 > 详细

Python新式类继承的C3算法

时间:2016-07-05 18:25:02      阅读:349      评论:0      收藏:0      [点我收藏+]

标签:

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

 

Python新式类继承的C3算法

标签:

原文地址:http://www.cnblogs.com/blackmatrix/p/5644023.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!