Skip to content

How to Order Multiple Inheritance in Python, and What is the Order of Execution?

In Python, the order of multiple inheritance is controlled by the class definition and is determined by the Method Resolution Order (MRO).


How can you control the order of multiple inheritance in Python, and what determines the order in which methods are executed?

1. Defining the Inheritance Order

When you define a class with multiple parents, the order in which you list those parent classes determines the MRO. The first class listed is checked first when searching for methods.

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):  # B is checked before C
    pass

d_instance = D()
print(d_instance.greet())  # Output: "Hello from B"

2. Understanding Method Resolution Order (MRO)

To see the MRO for any class, you can use the mro() method or the __mro__ attribute:

print(D.mro())       # Output: [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
print(D.__mro__)     # Same as above

The MRO indicates that:

  1. D checks B first,
  2. Then checks C,
  3. Then checks A,
  4. Finally checks the base class object.

3. Changing the Inheritance Order

If you want to prioritize a different class, simply change the order in which you list the parent classes in your definition.

class D(C, B):  # Now C is checked before B
    pass

d_instance = D()
print(d_instance.greet())  # Output: "Hello from C"

Summary of Execution Order

  1. First: Check the first parent class.
  2. Second: If the method isn’t found, check the next parent in the order.
  3. Continue: This continues down the MRO until a method is found or all classes are checked.
  4. Finally: If no method is found, Python raises an AttributeError.

Conclusion

By defining the order of parent classes in your class declaration, you control the MRO and thus the order of execution for methods in a multiple inheritance scenario.


Additonal

Example 1: Animal Classes

Imagine a scenario with different types of animals and their sounds.

class Animal:
    def sound(self):
        return "Some generic sound"

class Dog(Animal):
    def sound(self):
        return "Bark"

class Cat(Animal):
    def sound(self):
        return "Meow"

class Poodle(Dog):
    def sound(self):
        return "Woof"

class PersianCat(Cat):
    def sound(self):
        return "Purr"

class Pet(Poodle, PersianCat):
    pass

pet = Pet()
print(pet.sound())  # Output: "Woof"
print(Pet.mro())    # Output: [<class '__main__.Pet'>, <class '__main__.Poodle'>, <class '__main__.PersianCat'>, <class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>]
  • When calling pet.sound(), Python first checks Poodle (since it’s listed first), finds the sound method there, and executes it.
  • The MRO shows the order in which Python checks for methods.

Example 2: Working with Vehicles

Consider a scenario involving different types of vehicles.

class Vehicle:
    def drive(self):
        return "Driving a vehicle"

class Car(Vehicle):
    def drive(self):
        return "Driving a car"

class Truck(Vehicle):
    def drive(self):
        return "Driving a truck"

class ElectricCar(Car):
    def drive(self):
        return "Driving an electric car"

class HybridTruck(Truck):
    pass

class SuperTruck(HybridTruck, ElectricCar):
    pass

super_truck = SuperTruck()
print(super_truck.drive())  # Output: "Driving a truck"
print(SuperTruck.mro())      # Output: [<class '__main__.SuperTruck'>, <class '__main__.HybridTruck'>, <class '__main__.Truck'>, <class '__main__.Vehicle'>, <class 'object'>]
  • In this case, SuperTruck inherits from HybridTruck (which in turn inherits from Truck). The drive method from Truck is called because it's higher up the hierarchy compared to ElectricCar.

Example 3: Mixing Behaviors

Let’s create a scenario where we mix different behaviors using multiple inheritance.

class Swimmer:
    def swim(self):
        return "Swimming"

class Flyer:
    def fly(self):
        return "Flying"

class Duck(Swimmer, Flyer):
    def quack(self):
        return "Quack"

duck = Duck()
print(duck.swim())  # Output: "Swimming"
print(duck.fly())   # Output: "Flying"
print(duck.quack()) # Output: "Quack"
print(Duck.mro())    # Output: [<class '__main__.Duck'>, <class '__main__.Swimmer'>, <class '__main__.Flyer'>, <class 'object'>]
  • Here, Duck inherits both swimming and flying behaviors from Swimmer and Flyer. It showcases how multiple inheritance allows a class to combine functionalities from different classes.

Summary

These examples illustrate how multiple inheritance works in Python, how methods are resolved based on the MRO, and how you can effectively design your classes to leverage multiple inheritance for combining behaviors and functionalities.