Bird
Raised Fist0
Pythonprogramming~15 mins

Method Resolution Order (MRO) in Python - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - Method Resolution Order (MRO)
What is it?
Method Resolution Order (MRO) is the order in which Python looks for a method or attribute in a hierarchy of classes when you use inheritance. It decides which method to call when multiple classes have methods with the same name. This helps Python know exactly where to find the right method to run. MRO is especially important in multiple inheritance, where a class inherits from more than one parent class.
Why it matters
Without MRO, Python wouldn't know which method to use when multiple parent classes have methods with the same name. This would cause confusion and errors in programs, making it hard to reuse code safely. MRO ensures that method calls are predictable and consistent, which helps developers build complex systems with multiple inheritance without unexpected behavior.
Where it fits
Before learning MRO, you should understand basic classes and inheritance in Python. After MRO, you can explore advanced topics like super() function, multiple inheritance design patterns, and Python's class internals.
Mental Model
Core Idea
MRO is the rule Python follows to find the first method or attribute in a class hierarchy when multiple classes define it.
Think of it like...
Imagine a group of friends standing in a line to answer a question. The first friend in line who knows the answer responds. MRO is like that line order deciding who answers first.
Class hierarchy and MRO order:

  ┌─────────┐
  │  ClassA │
  └─────────┘
      ▲
      │
  ┌─────────┐      ┌─────────┐
  │  ClassB │─────▶│  ClassC │
  └─────────┘      └─────────┘
      ▲                ▲
      │                │
      └───────┬────────┘
              │
          ┌─────────┐
          │ ClassD  │
          └─────────┘

MRO for ClassD: [ClassD, ClassB, ClassC, ClassA, object]
Build-Up - 7 Steps
1
FoundationUnderstanding Single Inheritance Lookup
🤔
Concept: How Python finds methods in a simple parent-child class relationship.
When a class inherits from one parent, Python looks for a method in the child first. If it doesn't find it, Python looks in the parent class. This is a straight line search upwards in the class tree.
Result
Python calls the method from the child if it exists; otherwise, it uses the parent's method.
Understanding this simple lookup is the base for grasping how Python searches methods when inheritance is involved.
2
FoundationBasics of Multiple Inheritance
🤔
Concept: Introducing classes that inherit from more than one parent and the need for a search order.
When a class inherits from two or more classes, Python needs a clear order to check each parent for a method. Without a rule, Python wouldn't know which parent's method to use if both have the same method name.
Result
Python uses a specific order to check parents, which is the Method Resolution Order (MRO).
Knowing that multiple inheritance creates ambiguity helps understand why MRO is necessary.
3
IntermediateHow Python Calculates MRO with C3 Linearization
🤔Before reading on: do you think Python checks parents left-to-right or uses a more complex rule? Commit to your answer.
Concept: Python uses a special algorithm called C3 linearization to create a consistent MRO list that respects inheritance order and avoids conflicts.
C3 linearization merges the MROs of parent classes and the list of parents themselves into a single order. It ensures that a class always appears before its parents and that the order respects the left-to-right declaration of parents.
Result
Python produces a linear list of classes to check for methods, ensuring no contradictions in method lookup.
Understanding C3 linearization explains why Python's MRO is predictable and consistent even in complex inheritance trees.
4
IntermediateUsing __mro__ and mro() to Inspect Order
🤔Before reading on: do you think Python provides a way to see the MRO of a class? Commit to your answer.
Concept: Python offers built-in ways to see the MRO of any class using __mro__ attribute and mro() method.
You can print ClassName.__mro__ or call ClassName.mro() to get a tuple or list showing the order Python uses to look up methods. This helps debug and understand inheritance behavior.
Result
You get a clear list of classes in the order Python searches for methods.
Knowing how to inspect MRO helps you verify and debug complex inheritance structures.
5
IntermediateRole of super() in Method Resolution
🤔Before reading on: does super() always call the parent class method directly? Commit to your answer.
Concept: The super() function uses MRO to call the next method in the order, not necessarily the immediate parent.
When you use super().method(), Python looks up the MRO list and calls the next method after the current class. This allows cooperative multiple inheritance where all classes can contribute behavior.
Result
super() enables methods in multiple classes to be called in a controlled order.
Understanding super() in terms of MRO clarifies how multiple inheritance can work smoothly without skipping methods.
6
AdvancedMRO Conflicts and Resolution Errors
🤔Before reading on: do you think all multiple inheritance combinations are allowed? Commit to your answer.
Concept: Sometimes, Python cannot create a consistent MRO due to conflicting inheritance orders, causing errors.
If parent classes have incompatible orders, Python raises a TypeError about MRO conflict. This means the inheritance graph is ambiguous and cannot be linearized.
Result
Python prevents ambiguous method lookups by refusing to create classes with conflicting MROs.
Knowing about MRO conflicts helps avoid designing inheritance trees that cause runtime errors.
7
ExpertInternal Implementation of MRO in CPython
🤔Before reading on: do you think MRO is computed once or every time a method is called? Commit to your answer.
Concept: CPython computes the MRO once when the class is created and caches it for fast method lookup during runtime.
When a class is defined, CPython runs the C3 linearization algorithm and stores the MRO in the class's __mro__ attribute. Method calls then use this cached order to quickly find methods without recomputing.
Result
Method calls are efficient because MRO is precomputed and reused.
Understanding that MRO is cached explains why method lookup is fast despite complex inheritance.
Under the Hood
Python uses the C3 linearization algorithm to create a single, linear order of classes for method lookup. This order respects the inheritance hierarchy and the order of base classes. When a method is called, Python checks each class in this order until it finds the method. The MRO is computed once when the class is created and stored in the __mro__ attribute for fast access during method calls.
Why designed this way?
C3 linearization was chosen because it guarantees a consistent and monotonic order that respects both local precedence order and global hierarchy. Earlier methods like depth-first or breadth-first search caused ambiguity and inconsistent results. C3 avoids these problems, making multiple inheritance predictable and safe.
Class creation and method lookup flow:

┌───────────────┐
│ Define Class  │
└──────┬────────┘
       │
       ▼
┌───────────────────────────┐
│ Compute MRO with C3 Linear │
│ Store in __mro__ attribute │
└────────────┬──────────────┘
             │
             ▼
┌───────────────────────────┐
│ Method call on instance   │
│ Check classes in __mro__  │
│ in order until method found│
└───────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does super() always call the immediate parent class method? Commit to yes or no.
Common Belief:super() always calls the method of the immediate parent class.
Tap to reveal reality
Reality:super() calls the next method in the MRO, which may not be the immediate parent if multiple inheritance is involved.
Why it matters:Misunderstanding super() can lead to skipping methods or calling the wrong method, causing bugs in cooperative multiple inheritance.
Quick: Is the MRO order always left-to-right as classes are listed? Commit to yes or no.
Common Belief:Python checks parent classes strictly left-to-right in the inheritance list.
Tap to reveal reality
Reality:Python uses C3 linearization, which respects left-to-right order but also merges parent MROs to maintain consistency, so the order can differ from simple left-to-right.
Why it matters:Assuming simple left-to-right lookup can cause confusion when methods are resolved in unexpected order.
Quick: Can any combination of multiple inheritance classes be used without error? Commit to yes or no.
Common Belief:You can combine any classes in multiple inheritance without problems.
Tap to reveal reality
Reality:Some combinations cause MRO conflicts, and Python raises errors to prevent ambiguous method resolution.
Why it matters:Ignoring this can cause runtime errors and crashes, making code unreliable.
Quick: Does Python recompute MRO every time a method is called? Commit to yes or no.
Common Belief:Python calculates MRO each time a method is called to find the right method.
Tap to reveal reality
Reality:Python computes MRO once when the class is created and caches it for efficient method lookup.
Why it matters:Thinking MRO is recomputed wastes mental effort and can lead to misunderstanding performance characteristics.
Expert Zone
1
MRO respects both local precedence (order of base classes) and monotonicity (no class appears before its parents), which is subtle but critical for consistent behavior.
2
Using super() correctly requires all classes in the hierarchy to cooperate by calling super(), otherwise method chains break.
3
Python's MRO algorithm is stable and deterministic, which means the order won't change unexpectedly even if the inheritance tree is complex.
When NOT to use
Avoid complex multiple inheritance when simpler composition or delegation can achieve the same goal. Use interfaces or mixins carefully. In some cases, design patterns like composition over inheritance or explicit method calls are better alternatives.
Production Patterns
In real-world Python code, MRO is used heavily in frameworks like Django and Flask for mixins and class-based views. Developers rely on MRO to combine behaviors cleanly. Understanding MRO helps debug issues with method overrides and super() calls in large codebases.
Connections
Linearization in Compiler Design
MRO uses a linearization algorithm similar to those used in compilers to order instructions or resolve dependencies.
Knowing about linearization in compilers helps understand why MRO must produce a consistent, conflict-free order.
Dependency Resolution in Package Managers
Both MRO and package managers resolve dependencies in a specific order to avoid conflicts and ensure consistency.
Understanding dependency resolution clarifies why MRO must carefully merge parent classes to avoid ambiguous method calls.
Organizational Hierarchies in Management
MRO is like deciding who reports to whom and who has authority when multiple managers are involved.
Seeing MRO as a chain of command helps grasp why order matters and why conflicts must be resolved.
Common Pitfalls
#1Calling super() without understanding MRO causes skipped methods.
Wrong approach:class A: def method(self): print('A') class B(A): def method(self): print('B') class C(A): def method(self): print('C') class D(B, C): def method(self): B.method(self) # directly calling B's method C.method(self) # directly calling C's method obj = D() obj.method()
Correct approach:class A: def method(self): print('A') class B(A): def method(self): print('B') super().method() class C(A): def method(self): print('C') super().method() class D(B, C): def method(self): print('D') super().method() obj = D() obj.method()
Root cause:Directly calling parent methods bypasses MRO and breaks cooperative method calls, causing unexpected behavior.
#2Assuming MRO is simple left-to-right order causes confusion.
Wrong approach:class X: pass class Y: pass class Z(X, Y): pass print(Z.__mro__) # Expecting [Z, X, Y, object] always, ignoring C3 linearization
Correct approach:print(Z.__mro__) # Actually shows the C3 linearized order, which may differ in complex cases
Root cause:Ignoring C3 linearization leads to wrong assumptions about method lookup order.
#3Creating inheritance trees with conflicting orders causes errors.
Wrong approach:class A: pass class B(A): pass class C(A): pass class D(B, C): pass class E(C, B): pass class F(D, E): pass # Raises TypeError: Cannot create a consistent method resolution order
Correct approach:Avoid conflicting inheritance orders or redesign classes to prevent MRO conflicts.
Root cause:Conflicting base class orders make it impossible for Python to linearize MRO.
Key Takeaways
Method Resolution Order (MRO) defines the exact order Python uses to find methods in a class hierarchy, especially with multiple inheritance.
Python uses the C3 linearization algorithm to create a consistent and predictable MRO that respects inheritance rules and avoids conflicts.
The super() function relies on MRO to call the next method in line, enabling cooperative multiple inheritance.
MRO is computed once when a class is created and cached for efficient method lookup during runtime.
Understanding MRO helps avoid common bugs, design better class hierarchies, and debug complex inheritance issues.

Practice

(1/5)
1. What does Method Resolution Order (MRO) in Python determine?
easy
A. The order Python compiles code
B. The order Python executes loops
C. The order Python looks for methods in inheritance
D. The order Python imports modules

Solution

  1. Step 1: Understand MRO purpose

    MRO defines the sequence Python follows to find methods in classes with inheritance.
  2. Step 2: Compare options

    Only The order Python looks for methods in inheritance correctly describes MRO's role in method lookup order.
  3. Final Answer:

    The order Python looks for methods in inheritance -> Option C
  4. Quick Check:

    MRO = method lookup order [OK]
Hint: MRO is about method search order in inheritance [OK]
Common Mistakes:
  • Confusing MRO with loop or import order
  • Thinking MRO controls code compilation
  • Mixing MRO with unrelated Python features
2. Which of the following is the correct way to check the MRO of a class MyClass in Python?
easy
A. print(MyClass.__mro__)
B. print(MyClass.get_mro())
C. print(MyClass.MRO())
D. print(MyClass.mro)

Solution

  1. Step 1: Recall MRO access methods

    Python provides __mro__ attribute and mro() method to check MRO.
  2. Step 2: Identify correct syntax

    MyClass.__mro__ is a tuple showing MRO; MyClass.mro() is a method returning a list. print(MyClass.__mro__) uses __mro__ correctly with print.
  3. Final Answer:

    print(MyClass.__mro__) -> Option A
  4. Quick Check:

    Use __mro__ attribute to check MRO [OK]
Hint: Use ClassName.__mro__ to see MRO tuple [OK]
Common Mistakes:
  • Using non-existent get_mro() method
  • Forgetting parentheses for mro() method
  • Trying to print mro without calling it
3. What will be the output of the following code?
class A:
    def greet(self):
        return 'Hello from A'

class B(A):
    def greet(self):
        return 'Hello from B'

class C(A):
    def greet(self):
        return 'Hello from C'

class D(B, C):
    pass

print(D().greet())
medium
A. 'Hello from B'
B. 'Hello from A'
C. 'Hello from C'
D. Error: Ambiguous method

Solution

  1. Step 1: Determine MRO of class D

    Class D inherits from B and C. Python uses C3 linearization: D > B > C > A.
  2. Step 2: Find first greet method in MRO

    Method greet is found first in B, so D().greet() calls B's greet method.
  3. Final Answer:

    'Hello from B' -> Option A
  4. Quick Check:

    MRO order picks B's greet first [OK]
Hint: MRO checks parents left to right, first method wins [OK]
Common Mistakes:
  • Assuming C's greet is called instead of B's
  • Thinking A's greet is called directly
  • Expecting an error due to multiple inheritance
4. Consider the following code snippet. What is the error and how to fix it?
class X:
    def method(self):
        return 'X'

class Y:
    def method(self):
        return 'Y'

class Z(X, Y):
    def method(self):
        return super().method()

print(Z().method())
medium
A. Error: super() call is ambiguous; fix by specifying class and self
B. Output: 'X' (no error)
C. Output: 'Y' (no error)
D. Error: Missing parentheses in print statement

Solution

  1. Step 1: Analyze super() in Z.method()

    super() calls next method in MRO after Z, which is X.method().
  2. Step 2: Check output of X.method()

    X.method() returns 'X', so print outputs 'X' with no error.
  3. Final Answer:

    Output: 'X' (no error) -> Option B
  4. Quick Check:

    super() calls next in MRO, here X.method() [OK]
Hint: super() calls next method in MRO automatically [OK]
Common Mistakes:
  • Thinking super() needs explicit class and self
  • Expecting output 'Y' instead of 'X'
  • Assuming syntax error in print statement
5. Given the classes below, what is the MRO of class F?
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
class E(C, B): pass
class F(D, E): pass
hard
A. (F, E, D, B, C, A, object)
B. (F, D, E, B, C, A, object)
C. (F, D, B, C, E, C, B, A, object)
D. TypeError due to inconsistent MRO

Solution

  1. Step 1: Understand MRO consistency rules

    Python requires MRO to be consistent and follow C3 linearization rules.
  2. Step 2: Check classes D and E inheritance

    D inherits B then C; E inherits C then B. This creates conflicting order for F inheriting D and E.
  3. Step 3: Result of conflict

    Python raises TypeError for class F due to inconsistent MRO from conflicting parent orders.
  4. Final Answer:

    TypeError due to inconsistent MRO -> Option D
  5. Quick Check:

    Conflicting parent order causes TypeError [OK]
Hint: Conflicting parent order causes MRO TypeError [OK]
Common Mistakes:
  • Assuming Python picks one MRO silently
  • Ignoring C3 linearization rules
  • Trying to list MRO despite conflict