Inheritance is one of the fundamental concepts in object-oriented programming (OOP) that allows a class to inherit attributes and methods from another class. In Python, inheritance can be extended beyond the typical single inheritance, where a class inherits from just one parent, to multiple inheritance, where a class inherits from two or more parent classes simultaneously.
Understanding multiple inheritance unlocks powerful design patterns and code reuse techniques but also introduces complexity that requires careful handling. This lesson will guide you through the essentials of multiple inheritance in Python, how it works under the hood, practical examples, potential pitfalls, and best practices to master this concept.
What Is Multiple Inheritance?
Simply put, multiple inheritance allows a new class (called a child class or subclass) to inherit features from more than one base class. This means the subclass gains all attributes and methods from all its parents.
In Python, you define multiple inheritance by listing multiple parent classes inside the parentheses when declaring a new class:
📌 Deep Dive: Basic Syntax of Multiple Inheritance
class Parent1:
def method1(self):
print("Method from Parent1")
class Parent2:
def method2(self):
print("Method from Parent2")
class Child(Parent1, Parent2):
pass
c = Child()
c.method1()
c.method2()
Here, Child inherits from both Parent1 and Parent2. As a result, it has access to both method1 and method2.
Why Use Multiple Inheritance?
Multiple inheritance can be extremely useful when you want to combine reusable features from different classes without rewriting code. Consider these scenarios:
- Mixing behaviors: A class can combine behaviors from multiple sources, such as logging, serialization, or GUI features.
- Code reuse: You avoid duplication by inheriting common functionality from several classes.
- Extending functionality: You can add or override specific methods while keeping others intact from multiple parents.
However, while powerful, multiple inheritance can also make code more complex and harder to debug if not used thoughtfully. We will explore these complexities further below.
Understanding Python’s Method Resolution Order (MRO)
One of the biggest challenges with multiple inheritance is determining which method to call if multiple parent classes define methods with the same name. Python solves this with a well-defined Method Resolution Order (MRO), which is the order in which Python looks for methods and attributes.
The MRO follows the C3 linearization algorithm, which guarantees a consistent and predictable order of method lookup. You can view the MRO of any class by calling the mro() method or using the built-in attribute __mro__.
📌 Deep Dive: Inspecting MRO in Python
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
print("Hello from B")
class C(A):
def greet(self):
print("Hello from C")
class D(B, C):
pass
print(D.mro())
The MRO list shows the order Python checks when calling methods on an instance of D. If greet is called, Python will first look in D, then B, then C, and finally A. The first method found will be executed.

When Method Names Collide
Because multiple inheritance brings together features from different classes, it’s common to encounter method name collisions. Consider this example:
📌 Deep Dive: Method Name Collision Example
class X:
def do_something(self):
print("do_something in X")
class Y:
def do_something(self):
print("do_something in Y")
class Z(X, Y):
pass
z = Z()
z.do_something()
Since Z inherits from both X and Y, and both have a do_something method, Python uses the MRO to decide which method to call. Here, it calls X's method because X is listed first in Z's inheritance list.
💡 Tip: Order Matters
When defining a class with multiple base classes, the order in which you list parent classes determines the method resolution order. The leftmost parent is searched first.
Using super() in Multiple Inheritance
One common source of confusion and bugs in multiple inheritance is using the super() function. Unlike in single inheritance, where super() simply calls the parent class method, in multiple inheritance it invokes the next method in the MRO chain.
This allows cooperative multiple inheritance, where parent classes cooperate by calling super() so that all relevant methods get executed in the MRO order.
📌 Deep Dive: Cooperative Method Calls with super()
class A:
def process(self):
print("Process in A")
class B(A):
def process(self):
print("Process in B before super()")
super().process()
print("Process in B after super()")
class C(A):
def process(self):
print("Process in C before super()")
super().process()
print("Process in C after super()")
class D(B, C):
def process(self):
print("Process in D before super()")
super().process()
print("Process in D after super()")
d = D()
d.process()
Here, each class calls super().process(), which follows the MRO. This way, all the process methods are executed in a controlled order without explicitly naming parent classes.
💡 Why Use super()?
Using super() in multiple inheritance ensures that all parent classes get their chance to run their methods. This makes the code cleaner and less error-prone than explicitly calling each parent class.
Potential Pitfalls and How to Avoid Them
While multiple inheritance provides great flexibility, it comes with challenges that beginners need to be aware of:
- Diamond Problem: When two parent classes inherit from the same grandparent class, it may cause ambiguity in method calls. Python's MRO handles this, but it's good to understand the concept.
- Name collisions: Different parent classes may have methods or attributes with the same name, leading to confusion unless the MRO is clearly understood.
- Complex debugging: Tracing errors through multiple inheritance chains can be difficult.
⚠️ Diamond Problem Explained
Consider the classic “diamond” inheritance shape, where class D inherits from classes B and C, which both inherit from A. Without MRO, calling a method from A could be ambiguous.
Python’s MRO ensures A's method is called only once in the correct order, preventing duplication and ambiguity.
| Aspect | Single Inheritance | Multiple Inheritance |
|---|---|---|
| Number of Parent Classes | One | Two or more |
| Method Resolution | Simple, straightforward | Uses MRO (C3 linearization) |
| Complexity | Lower | Higher, potential method name collisions |
| Code Reuse | Limited to one parent | Combines features from multiple parents |
| Use Cases | Simple hierarchies | Mixins, complex behavior combination |
Best Practices for Using Multiple Inheritance
To make the most of multiple inheritance without falling into common traps, keep these guidelines in mind:
- Prefer Mixins: Use multiple inheritance primarily for mixins — small classes that provide specific, reusable functionality without creating complex hierarchies.
- Use super() consistently: Always call
super()in overridden methods to maintain cooperative behavior. - Keep it simple: Avoid deep and complicated inheritance trees. Favor composition if appropriate.
- Name methods clearly: To reduce collisions, use distinct method names or namespaces where possible.
- Understand MRO: Always check the MRO using
ClassName.mro()to predict method lookup order.
Summary
Multiple inheritance in Python is a powerful tool that allows classes to inherit from multiple parents, combining behaviors and enabling flexible designs. It relies on the method resolution order (MRO) to determine which methods are called when there are name collisions.
By using super() and following best practices, you can leverage multiple inheritance effectively, writing clean, maintainable, and reusable code. However, always be cautious to avoid complexity and ambiguity, and prefer mixins or composition when suitable.
As you practice, try experimenting with your own multiple inheritance hierarchies, inspecting the MRO, and using super() to build cooperative classes. This hands-on experience is invaluable.
Quick Knowledge Check
Test what you just learned
Question 1 of 2
What determines the order Python looks for a method when a class inherits from multiple parents?
Question 2 of 2
When overriding methods in multiple inheritance, what is the recommended way to ensure all parent methods get called?
Loading results...