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,直到所有点都被遍历

       举个几个例子:

               

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

          

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

                         

  • 相关阅读:
    数据绑定表达式语法(Eval,Bind区别)
    使用博客园的第一件事 自定义主题
    sql2000 跨服务器复制表数据
    使用UpdatePanel 局部刷新出现中文乱码的解决方法!!
    MMC不能打开文件MSC文件
    sql 日期 、时间相关
    loaded AS2 swf call function in AS3 holder
    Rewrite the master page form action attribute in asp.net 2.0
    100万个不重复的8位的随机数
    flash 中实现斜切变型
  • 原文地址:https://www.cnblogs.com/yanghh/p/13224397.html
Copyright © 2011-2022 走看看