How does Python's Method Resolution Order (MRO) work, and what is the C3 linearization algorithm?
Python resolves method lookups by computing a linearized list of classes called the MRO using the C3 linearization algorithm, which guarantees that a class always appears before its parents and that the local precedence order declared in each class definition is preserved. You can inspect it via `ClassName.__mro__` or `ClassName.mro()`.
How to think about it
What the interviewer is really checking
MRO questions show up when interviewers probe whether you understand multiple inheritance — a corner of Python that’s easy to get wrong. The key is explaining why C3 exists (naive depth-first search breaks diamond inheritance) and being able to read the MRO of a class rather than reciting the algorithm mechanically.
The problem C3 solves
Before C3, Python used depth-first, left-to-right search. For diamond inheritance:
A
/ \
B C
\ /
D
Depth-first would give D → B → A → C. This means if A defines a method, C’s override is never reached — A is visited before C. C3 fixes this by pushing base classes toward the end so all immediate subclasses are checked first.
C3 linearization — two rules
C3 merges the parent MROs while enforcing:
- A class always appears before all of its parents.
- The left-to-right order of bases in the class definition is preserved.
For class D(B, C) where both B and C inherit from A, the result is [D, B, C, A, object].
Working through the diamond example
Cooperative inheritance with super()
super() does not call “the parent class” — it calls the next class in the MRO. This enables the cooperative pattern above where every class in a chain calls the next without needing to know what it is:
class B(A):
def greet(self) -> str:
return "B+" + super().greet() # calls C.greet next, not A.greet
class C(A):
def greet(self) -> str:
return "C+" + super().greet() # calls A.greet
print(D().greet()) # "B+C+A"
The key insight
Without C3, multiple inheritance in Python was fragile. With C3, the MRO is deterministic and consistent. The practical takeaway: when you call super(), you are not calling your parent — you are calling the next class in the linearized MRO, which may be a sibling class you did not write. This is why every class in a cooperative hierarchy must call super().