【问题标题】:Does Python's MRO, C3 linearization work depth-first? Empirically it does notPython 的 MRO、C3 线性化是否深度优先?经验上不
【发布时间】:2016-11-08 02:50:58
【问题描述】:

我正在阅读Python Multiple Inheritance (on Programiz),然后我发现了这个 StackOverflow 问题,Method Resolution Order (MRO) in new-style classes?,但在这个问题中,像 Alex Martelli 这样的一些程序员说它使用深度优先方法,我对此表示怀疑。

例子:

class H():
    def m(self):
        print("H")

class G(H):
    def m(self):
        print("G")
        super().m()

class I(G):
    def m(self):
        print("I")
        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()

x = A()
x.m()

因此,如果我基于 MRO 构建图表,那么根据深度优先它应该遵循以下内容:

路径应该是:

A-->B-->C-->E-->F-->G-->D-->H

但是如果你运行上面的代码你会得到:

A
B
C
E
D
F
G
H

因为它走的是这条路:

A-->B-->C-->E-->D-->F-->G-->H

现在我对节点 "D" 或类 "D" 产生了混淆

这是怎么回事?

【问题讨论】:

    标签: python python-3.x graph method-resolution-order


    【解决方案1】:

    路径应该是:

    A-->B-->C-->E-->F-->G-->D-->H

    F 不能在 D 之前 - 这将是一个矛盾 - 参见 D 类。

    C3线性化算法的工作方式,你必须对父母进行线性化,然后,只要没有矛盾,你就可以对孩子进行线性化。所以我一次线性化这些,从父母开始。在我们到达 C 和 A 之前,大多数都是微不足道的:

    class PrettyType(type):
        """make the repr of the classes look nice when finally listed"""
        def __repr__(self):
            return self.__name__
    
    # subclasses of O will also have the metaclass:
    class O(metaclass=PrettyType): 'O, object'
    
    class H(O): 'H, O, object'
    # H's parent is O
    
    class G(H): 'G, H, O, object'
    # G's linearization is itself followed by its parent's linearization.
    
    class I(G): 'I, G, H, O, object'
    # I's linearization is I followed by G's
    
    class F(H): 'F, H, O, object'
    
    class E(H): 'E, H, O, object'
    
    class D(F): 'D, F, H, O, object'
    
    class C(E, F, G): 'C, E, F, G, H, O, object' 
    # C's linearization is C followed by a consistent linearization of 
    # its parents, left to right. 
    # First C, then E - then you might be tempted to put H after E,
    # but H must come after F and G (see class F and G)
    # so we try F's linearization, noting that H comes after G,
    # so we try G's linearization, H then consistently comes next, then object
    
    class B(O): 'B, O, object'
    

    A 是:

    class A(B, C, D): 'A, B, C, E, D, F, G, H, O, object'
    # final complex case -      ^--^ can't go from E to F 
    #                                D must come before F (see class D)
    #                              ^--^ After D, can do F, 
    #                                    then finish with C's MRO 
    #                                    with no contradictions 
    

    正如我所解释的那样,这 3 个标准是:

    1. 父母的 MRO 保持一致
    2. 本地 MRO 保持一致
    3. 无周期性

    算法,正如我所说,是你从左到右尊重父母,但首先深入,除非你会得到一个被孩子阻止的共享父母(例如,F被它的孩子阻止,D)在这种情况下你会寻找其他候选人(那么D,不矛盾,很好,然后你可以选择F和C的MRO的其余部分。)

    >>> A.mro()
    [A, B, C, E, D, F, G, H, O, <class 'object'>]
    

    直接线性化,无需先线性化双亲

    我们可以通过避免矛盾来完成线性化。

    再次,

    • 从左到右
    • 深度优先 - 除非共享父级被阻止(必须能够返回)
    • 不允许循环关系

    【讨论】:

    • 如此简洁易懂!投票不够高。 3 行总结很棒
    • 如果你能最喜欢的答案,我会这样做!
    猜你喜欢
    • 1970-01-01
    • 2017-12-22
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 2010-10-15
    • 1970-01-01
    相关资源
    最近更新 更多