Skip to content
Advertisement

Why is “Y” printed instead of “X” in this MRO?

Could somebody explain why this code prints Y and not X? I expected it to print “X” because it says pass in Class C and Class X is the next super class.

class X:
def foo(self):
    return "X"

class Y:
    def foo(self):
        return "Y"

class A(X):
    def foo(self):
        return self.met()

class B(A):
    def foo(self):
        return "B"

class C(X):
    pass

class D(C, X):
    def met(self):
        return "D"

class E(A, D):
    def foo(self):
        return super().foo()

class F(Y,B):
    pass

class G(D, B):
    pass

class H(E, A, X):
     def met(self):
        return "H"

class I(G,F):
    pass
print(I().foo())

Sorry for the long code, but I dont know how to make it shorter without making the question unclear

Advertisement

Answer

Per Python Multiple Inheritance: The Diamond Rule:

  1. List all the base classes, following the classic lookup rule and include a class multiple times if it’s visited repeatedly. In the above example, the list of visited classes is [D, B, A, C, A].
  2. Scan the list for duplicated classes. If any are found, remove all but one occurrence, leaving the last one in the list. In the above example, the list becomes [D, B, C, A] after dropping duplicates.
m = ['I', 'G', 'D', 'C', 'X', 'object', 'X', 'object', 'B', 'A', 
     'X', 'object', 'F', 'Y', 'object', 'B', 'A', 'X', 'object']
s = set()
custom_mro = [i for i in reversed(m) if not (i in s or s.add(i))][::-1]
original_mro = list(i.__name__ for i in I.__mro__)

assert custom_mro == original_mro
print(custom_mro) #['I', 'G', 'D', 'C', 'F', 'Y', 'B', 'A', 'X', 'object']

Y is printed because Y class is listed first on the mro order.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement