什么是 Python 中的钻石问题,为什么它没有出现在 python2 中?

Mar*_*ann 1 python diamond-problem python-2.7 python-3.x

我得到了这个代码:

class A:
 pass

class B(A):
 pass

class C(A):
 pass

class D(A,B):
 pass

d = D()
Run Code Online (Sandbox Code Playgroud)

在 Python3 中,我收到 MRO 错误。我的意思是它出现是因为钻石问题。在 Python2 中没有问题。为什么会这样,这个钻石问题究竟是什么?

gmd*_*mds 9

不是钻石问题!

当两个类具有共同的祖先,而另一个类将这两个类都作为基类时,就会出现菱形问题,例如:

class A:
    def do_thing(self):
        print('From A')

class B(A):
    def do_thing(self):
        print('From B')

class C(A):
    def do_thing(self):
        print('From C')

class D(B, C):
    pass

d = D()
d.do_thing()
Run Code Online (Sandbox Code Playgroud)

在某些语言中,由于继承是如何实现的,当您调用 时d.do_thing(),您实际上想要覆盖的from还是from是不明确的do_thingBC

由于方法解析顺序, Python 没有这个问题。简而言之,当您从多个类继承时,如果它们的方法名称冲突,则命名的第一个优先。既然我们已经指定了D(B, C)B.do_thing就在之前被调用C.do_thing

这也是你遇到这个问题的原因。考虑一下:由于在您的示例中B继承自A,因此B's 方法将在A's之前。假设我们有另一个类,B_derived,它继承自B。方法解析顺序如下:

B_derived -> B -> A
Run Code Online (Sandbox Code Playgroud)

现在,我们D代替了B_derived,因此我们可以将其替换为:

D -> B -> A
Run Code Online (Sandbox Code Playgroud)

但是,请注意,您还指定了DAbefore继承B,并且根据上述规则,在方法解析顺序中A也必须B位于之前。这意味着我们得到了一个不一致的链:

D -> A -> B -> A
Run Code Online (Sandbox Code Playgroud)

,而不是钻石问题,是您收到错误的原因。

(另请参阅此答案)。