zoukankan      html  css  js  c++  java
  • MRO

    对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法

    所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution Order,或MRO)。对于只支持单继承的语言来说,MRO 一般比较简单;

    而对于 Python 这种支持多继承的语言来说,MRO 就复杂很多。

    先看一个「菱形继承」的例子:

    如果 x 是 D 的一个实例,那么 x.show() 到底会调用哪个 show 方法呢?

        1)如果按照 [D, B, A, C] 的搜索顺序,那么 x.show() 会调用 A.show();

        2)如果按照 [D, B, C, A] 的搜索顺序,那么 x.show() 会调用 C.show()。

    由此可见,MRO 是把类的继承关系线性化的一个过程,而线性化方式决定了程序运行过程中具体会调用哪个方法。

    既然如此,那什么样的 MRO 才是最合理的?Python 中又是如何实现的呢?

    Python 至少有三种不同的 MRO:

        1)经典类(classic class)的深度遍历。

        2)Python 2.2 的新式类(new-style class)预计算。

        3)Python 2.3 的新式类的 C3 算法。它也是 Python 3 唯一支持的方式。

    1. 经典类中的 MRO

       Python 有两种类:经典类(classic class)和新式类(new-style class)。两者的不同之处在于新式类继承自 object。

           1)在 Python 2.1 以前,经典类是唯一可用的形式;

           2)Python 2.2 引入了新式类,使得类和内置类型更加统一;

           3)在 Python 3 中,新式类是唯一支持的类。

       经典类采用了一种很简单的 MRO 方法:从左至右的深度优先遍历。以上述「菱形继承」为例,其查找顺序为 [D, B, A, C, A],如果只保留重复

       类的第一个则结果为 [D,B,A,C]。我们可以用 inspect.getmro(class) 来获取类的 MRO。

    class A:
        def show(self):
            print("A.show()")
    
    class B(A):
        pass
    
    class C(A):
        def show(self):
            print("C.show()")
    
    class D(B, C):
        pass
    
    x = D()
    x.show()

       这种深度优先遍历对于简单的情况还能处理的不错,但是对于上述「菱形继承」其结果却不尽如人意:虽然 C.show() 是 A.show() 的更具体化版

       本(显示了更多的信息),但我们的x.show() 没有调用它,而是调用了 A.show()。这显然不是我们希望的结果。对于新式类而言,所有的类都继

       承自 object,所以「菱形继承」是非常普遍的现象,因此不可能采用这种 MRO 方式。

    2. Python 2.2中的新式类 MRO

       为解决经典类 MRO 所存在的问题,Python 2.2 针对新式类提出了一种新的 MRO 计算方式:在定义类时就计算出该类的 MRO 并将其作为类的属性。

       因此新式类可以直接通过 __mro__ 属性获取类的 MRO。

       对于新式类的 MRO,将是自左向右的广度遍历,上述钻石继承的顺序就变成了 [D,B,C,A,object],解决了菱形继承(下面左图)在经典类中存在的问题。

       但是对于正常的继承关系(如下面右图),根据新式类中的广度遍历原则,查找顺序为[E,C,D,A,B,object],A 是 C 的唯一基类,但却在 C 之后先查询 D,

       根据单调性,应该先从唯一基类进行查找。

       注意:在 Python 2.2 到 Python3 之间的版本仍然存在经典类,在定义类时:

             1)继承 object 才是新式类,MRO 按从左向右的深度优先原则;

             2)没有继承 object 就是经典类,MRO 按从左向右的广度优先原则。

            

       对比一下,左侧为 Python 2 中的经典类运行结果,右侧为 Python 2 中的新式类运行结果:

                

    3. Python 2.3及其以后的新式类 MRO

       新式类的 MRO 使用 C3 算法,并且在Python 3中只存在新式类。Python 2.3及其以后的新式类 MRO,使用的是拓扑排序,在一个有向无环图中:

           1)从左到右选择一个入度为0的顶点并输出(入度:以某顶点为弧头,终止于该顶点的弧的数目)

           2)从网中删除此顶点以及所有出边

           3)重复步骤1、2,直到所有点都被遍历

       举个几个例子:

               

          ----------------------------------------------------------------------------------------------------------

          

          ----------------------------------------------------------------------------------------------------------

                         

  • 相关阅读:
    数据库表之间的联合查询
    c# 后台调前台的js
    oracle创建视图
    设置Crystal Report的FieldObject换行
    在XAML中转义大括号
    运行水晶报表报crdb_adoplus.dll不存在错误的解决方案
    网页面里动态添加linkbutton或者button
    正则表达式
    实现checkbox全选。html dom对象和jquery dom对象。
    手把手教你做关键词匹配项目(搜索引擎) 第二天
  • 原文地址:https://www.cnblogs.com/yanghh/p/13224397.html
Copyright © 2011-2022 走看看