I got this code:
class A:
pass
class B(A):
pass
class C(A):
pass
class D(A,B):
pass
d = D()
In Python3 i get a MRO Error. I mean it appears because the Diamond Problem. In Python2 its no Problem. Why is this the case, and what is this Diamond Problem exactly ?
This is not the diamond problem!
The diamond problem occurs when two classes have a common ancestor, and another class has both those classes as base classes, for example:
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()
In some languages, because of how inheritance is implemented, when you call d.do_thing()
, it is ambiguous whether you actually want the overridden do_thing
from B
, or the one from C
.
Python doesn't have this problem because of the method resolution order. Briefly, when you inherit from multiple classes, if their method names conflict, the first one named takes precedence. Since we have specified D(B, C)
, B.do_thing
is called before C.do_thing
.
That is also why you get that problem. Consider this: since B
inherits from A
in your example, B
's methods will come before A
's. Say we have another class, B_derived
, that inherits from B
. The method resolution order will then be as follows:
B_derived -> B -> A
Now, we have D
in the place of B_derived
, therefore we can substitute it in to get this:
D -> B -> A
However, note that you have also specified that D
inherits from A
before B
, and by the rule above, A
must also come before B
in the method resolution order. That means we get an inconsistent chain:
D -> A -> B -> A
This, and not the diamond problem, is why you get an error.
(See also this answer).