Multiple Inheritance & The MRO
Python is one of the few modern languages that supports Multiple Inheritance, allowing a single class to inherit from more than one parent. While powerful, it introduces complexities like the “Diamond Problem” and requires a clear understanding of how Python decides which parent’s method to execute.
1. Syntax & Mixins
Section titled “1. Syntax & Mixins”Multiple inheritance is defined by listing parents in a comma-separated list.
The Mixin Pattern
Section titled “The Mixin Pattern”A Mixin is a class that provides a specific “slice” of functionality but isn’t meant to be used on its own.
class JSONSerializable: def to_json(self): import json return json.dumps(self.__dict__)
class Loggable: def log(self): print(f"Log: {self.__dict__}")
# User inherits behavior from both Mixinsclass User(JSONSerializable, Loggable): def __init__(self, name): self.name = name
u = User("Alice")u.log()print(u.to_json())2. The Diamond Problem
Section titled “2. The Diamond Problem”What happens if Class A defines a method, and both Class B and Class C inherit from A and override that method? If Class D inherits from both B and C, which version of the method should it use?
This is the Diamond Problem. Python solves this using a strict ordering system.
3. Under the Hood: MRO & C3 Linearization
Section titled “3. Under the Hood: MRO & C3 Linearization”The Method Resolution Order (MRO) is the list of classes Python searches when you call a method. Python uses an algorithm called C3 Linearization to calculate this list.
The Rules of C3:
Section titled “The Rules of C3:”- Children come before Parents.
- Left Parents come before Right Parents (as listed in the
classdefinition). - Monotonicity: If a class appears before another in one hierarchy, it must appear before it in all related hierarchies.
class A: passclass B(A): passclass C(A): passclass D(B, C): pass
# You can view the MRO using the .mro() methodprint(D.mro())Result: [D, B, C, A, object]
Notice that B is checked before C because it was listed first in class D(B, C).
4. Why super() is smarter than you think
Section titled “4. Why super() is smarter than you think”In multiple inheritance, super() does not necessarily call the “Parent” class. It calls the next class in the MRO.
class A: def greet(self): print("A")
class B(A): def greet(self): print("B") super().greet()
class C(A): def greet(self): print("C") super().greet()
class D(B, C): def greet(self): print("D") super().greet()
d = D()d.greet()Output: D -> B -> C -> A
Even though B’s parent is A, B.greet() calls C.greet()! This ensures that every class in the hierarchy gets a chance to run its logic exactly once.
5. Summary Table
Section titled “5. Summary Table”| Term | Meaning |
|---|---|
| Multiple Inheritance | A class inheriting from more than one parent. |
| Mixin | A class designed to add a specific feature via inheritance. |
| Diamond Problem | Ambiguity caused by shared ancestors in a tree. |
| MRO | The search order Python uses to find methods. |
| C3 Linearization | The algorithm that calculates the MRO. |