Diamond Problem — Core Concepts
What Is the Diamond Problem?
The diamond problem occurs when a class inherits from two classes that share a common ancestor. The inheritance graph forms a diamond shape:
A
/ \
B C
\ /
D
Class D inherits from both B and C, which both inherit from A. The question is: when D calls a method defined in A (and possibly overridden by B and C), which version runs? Does A’s method execute once or twice?
Why It’s a Real Problem
In languages like C++, the diamond can cause genuine bugs:
- Duplicate state:
A.__init__runs twice — once throughB, once throughC— creating duplicate copies ofA’s attributes. - Ambiguous calls: If both
BandCoverrideA.method(), which override doesDget? - Silent data corruption: Two initializations of the same base class can overwrite each other’s data.
How Python Solves It: The MRO
Python uses the Method Resolution Order (MRO), computed by the C3 linearization algorithm. It creates a single, linear order for method lookup that visits each class exactly once.
For the diamond above, Python’s MRO is: D → B → C → A → object.
What This Means in Practice
- When
Dcallssuper().__init__(), it callsB.__init__. B.__init__callssuper().__init__(), which callsC.__init__(notA!).C.__init__callssuper().__init__(), which finally callsA.__init__.A.__init__is called exactly once.
The crucial insight: super() doesn’t mean “my parent.” It means “the next class in the MRO.” This is what prevents the duplicate call to A.
Why Other Languages Handle It Differently
| Language | Approach |
|---|---|
| Java | Forbids multiple class inheritance (interfaces only) |
| C++ | Allows it, uses virtual inheritance to opt into single-copy semantics |
| Ruby | Uses mixins with a linearized module chain (similar to Python’s MRO) |
| Scala | Uses linearized trait stacking |
| Python | C3 linearization with cooperative super() |
Java’s approach is the most restrictive — you simply can’t create the diamond with classes. C++ gives you the tools but requires manual virtual annotations to avoid duplicate bases.
Checking the MRO
You can always inspect the order Python will use:
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
When the Diamond Appears Unintentionally
The diamond shows up more often than you’d think:
- Every class inherits from
object. So any multiple inheritance creates at least a mini-diamond withobjectat the top. - Framework mixins often inherit from a common base. Django’s
Viewis the apex of many diamonds. - Standard library types like
OrderedDict(which inherits from bothdictand some mixin behaviors) have diamond patterns internally.
Common Misconception
“Multiple inheritance always causes the diamond problem.” Not true. The diamond only occurs when two parents share an ancestor. If your parents are completely independent classes, there’s no diamond and no ambiguity. The diamond is specifically about the shared ancestor.
Practical Guidelines
- Check the MRO when designing class hierarchies with multiple inheritance. Print
YourClass.__mro__to verify the order matches your expectations. - Always call
super()in methods you override — this is what makes the MRO work correctly. - Keep it shallow. Deep diamonds (4+ levels) become hard to reason about. Consider composition if the hierarchy gets complex.
- Use mixins. The cleanest diamond patterns involve one concrete base class plus lightweight mixins that add specific behaviors.
One thing to remember: Python’s diamond problem solution is the MRO — a linear ordering that visits each ancestor exactly once, computed automatically at class definition time. Call super(), and the MRO handles the rest.
See Also
- Python Abc Abstract Base Classes Why Python's ABC module is like a building inspector who checks your blueprints before construction begins
- Python Class Decorators Understand Class Decorators through an everyday analogy so Python behavior feels intuitive, not random.
- Python Composition Vs Inheritance Understand Composition Vs Inheritance through an everyday analogy so Python behavior feels intuitive, not random.
- Python Cooperative Multiple Inheritance Why Python classes can have multiple parents and still get along — like a kid learning different skills from each family member.
- Python Dataclasses Advanced Understand Dataclasses Advanced through an everyday analogy so Python behavior feels intuitive, not random.