• 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官方文档中是如此解释的:

    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'>]
  • 相关阅读:
    理清一下JavaScript面向对象思路
    IE的CSS渲染跟其它浏览器有什么不同
    页面元素的CSS渲染优先级
    push与createElement性能比较
    关于JavaScript的push()函数
    关于JavaScript的沙箱模式
    JavaScript SandBox沙箱设计模式
    用live()方法给新增节点绑定事件
    深入JavaScript对象创建的细节
    Keras class_weight和sample_weight用法
  • 原文地址:https://www.cnblogs.com/blackmatrix/p/5644023.html
Copyright © 2020-2023  润新知