代码之家  ›  专栏  ›  技术社区  ›  sateesh

新样式类中的方法解析顺序(MRO)?

  •  83
  • sateesh  · 技术社区  · 16 年前

    书中 有一个例子使用
    演示如何以经典解析顺序解析方法的旧式类,以及
    与新订单有什么不同。

    2.5.2. 下面是一个例子:

    class Base1(object):  
        def amethod(self): print "Base1"  
    
    class Base2(Base1):  
        pass
    
    class Base3(object):  
        def amethod(self): print "Base3"
    
    class Derived(Base2,Base3):  
        pass
    
    instance = Derived()  
    instance.amethod()  
    print Derived.__mro__  
    

    电话 instance.amethod() 印刷品 Base1 Base3 . 电话 Derived.__mro__ 印刷品:

    (<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)

    4 回复  |  直到 9 年前
        1
  •  191
  •   P i    11 年前

    当在“天真”、“深度优先”的方法中出现同一祖先类不止一次时,传统继承类与新类型类的分辨率顺序之间的关键差异出现了——例如,考虑“菱形继承”的情况:

    >>> class A: x = 'a'
    ... 
    >>> class B(A): pass
    ... 
    >>> class C(A): x = 'c'
    ... 
    >>> class D(B, C): pass
    ... 
    >>> D.x
    'a'
    

    >>> class A(object): x = 'a'
    ... 
    >>> class B(A): pass
    ... 
    >>> class C(A): x = 'c'
    ... 
    >>> class D(B, C): pass
    ... 
    >>> D.x
    'c'
    >>> 
    

    这里是新款,顺序是:

    >>> D.__mro__
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, 
        <class '__main__.A'>, <type 'object'>)
    

    具有 A 强制在其所有子类之后以解析顺序出现一次,以便覆盖(即C对成员的覆盖 x )实际工作是明智的。

    这是应该避免使用旧式类的原因之一:使用“菱形”模式的多重继承在它们身上不起作用,而在新样式中却起作用。

        2
  •  27
  •   Ben    11 年前

    明白了,看一看 C3 linearization

    class G():
        def m(self):
            print("G")
    
    class F(G):
        def m(self):
            print("F")
            super().m()
    
    class E(G):
        def m(self):
            print("E")
            super().m()
    
    class D(G):
        def m(self):
            print("D")
            super().m()
    
    class C(E):
        def m(self):
            print("C")
            super().m()
    
    class B(D, E, F):
        def m(self):
            print("B")
            super().m()
    
    class A(B, C):
        def m(self):
            print("A")
            super().m()
    
    
    #      A^
    #     / \
    #    B^  C^
    #   /| X
    # D^ E^ F^
    #  \ | /
    #    G
    

    你拿到B D C E F G了吗?

    x = A()
    x.m()
    

    经过大量的尝试和错误,我对C3线性化给出了一个非正式的图论解释,如下所示:(如果这是错误的,请告诉我。)

    考虑这个例子:

    class I(G):
        def m(self):
            print("I")
            super().m()
    
    class H():
        def m(self):
            print("H")
    
    class G(H):
        def m(self):
            print("G")
            super().m()
    
    class F(H):
        def m(self):
            print("F")
            super().m()
    
    class E(H):
        def m(self):
            print("E")
            super().m()
    
    class D(F):
        def m(self):
            print("D")
            super().m()
    
    class C(E, F, G):
        def m(self):
            print("C")
            super().m()
    
    class B():
        def m(self):
            print("B")
            super().m()
    
    class A(B, C, D):
        def m(self):
            print("A")
            super().m()
    
    # Algorithm:
    
    # 1. Build an inheritance graph such that the children point at the parents (you'll have to imagine the arrows are there) and
    #    keeping the correct left to right order. (I've marked methods that call super with ^)
    
    #          A^
    #       /  |  \
    #     /    |    \
    #   B^     C^    D^  I^
    #        / | \  /   /
    #       /  |  X    /   
    #      /   |/  \  /     
    #    E^    F^   G^
    #     \    |    /
    #       \  |  / 
    #          H
    # (In this example, A is a child of B, so imagine an edge going FROM A TO B)
    
    # 2. Remove all classes that aren't eventually inherited by A
    
    #          A^
    #       /  |  \
    #     /    |    \
    #   B^     C^    D^
    #        / | \  /  
    #       /  |  X    
    #      /   |/  \ 
    #    E^    F^   G^
    #     \    |    /
    #       \  |  / 
    #          H
    
    # 3. For each level of the graph from bottom to top
    #       For each node in the level from right to left
    #           Remove all of the edges coming into the node except for the right-most one
    #           Remove all of the edges going out of the node except for the left-most one
    
    # Level {H}
    #
    #          A^
    #       /  |  \
    #     /    |    \
    #   B^     C^    D^
    #        / | \  /  
    #       /  |  X    
    #      /   |/  \ 
    #    E^    F^   G^
    #               |
    #               |
    #               H
    
    # Level {G F E}
    #
    #         A^
    #       / |  \
    #     /   |    \
    #   B^    C^   D^
    #         | \ /  
    #         |  X    
    #         | | \
    #         E^F^ G^
    #              |
    #              |
    #              H
    
    # Level {D C B}
    #
    #      A^
    #     /| \
    #    / |  \
    #   B^ C^ D^
    #      |  |  
    #      |  |    
    #      |  |  
    #      E^ F^ G^
    #            |
    #            |
    #            H
    
    # Level {A}
    #
    #   A^
    #   |
    #   |
    #   B^  C^  D^
    #       |   |
    #       |   |
    #       |   |
    #       E^  F^  G^
    #               |
    #               |
    #               H
    
    # The resolution order can now be determined by reading from top to bottom, left to right.  A B C E D F G H
    
    x = A()
    x.m()
    
        3
  •  5
  •   Denis Otkidach    16 年前

    Base3 Base1

    class Base1(object):
        def amethod(self): print "Base1"
    
    class Base2(Base1):
        pass
    
    class Base3(Base1):
        def amethod(self): print "Base3"
    
    class Derived(Base2,Base3):
        pass
    
    instance = Derived()
    instance.amethod()
    
    
    class Base1:
        def amethod(self): print "Base1"
    
    class Base2(Base1):
        pass
    
    class Base3(Base1):
        def amethod(self): print "Base3"
    
    class Derived(Base2,Base3):
        pass
    
    instance = Derived()
    instance.amethod()
    

    现在它输出:

    Base3
    Base1
    

    阅读 this explanation 了解更多信息。

        4
  •  1
  •   jamessan    16 年前

    您看到这种行为是因为方法解析是深度优先,而不是广度优先。德维德的遗产看起来像

             Base2 -> Base1
            /
    Derived - Base3
    

    所以 instance.amethod()

    1. 查看Base2已从Base1继承,并检查Base1。Base1有一个 amethod ,所以它被称为。

    这反映在 Derived.__mro__ . 简单地迭代 并在找到要查找的方法时停止。