Python > Object-Oriented Programming (OOP) in Python > Inheritance > Method Resolution Order (MRO)
Understanding Method Resolution Order (MRO) in Python
This snippet demonstrates how Python resolves method calls in a class hierarchy using the Method Resolution Order (MRO). MRO defines the order in which base classes are searched when executing a method call. Understanding MRO is crucial for writing robust and predictable code when using inheritance, especially with multiple inheritance.
Basic Inheritance Example
This code demonstrates basic inheritance. `Dog` and `Cat` inherit from `Animal`. Each subclass overrides the `speak` method, providing a specific implementation. When `mydog.speak()` is called, Python looks for the `speak` method in the `Dog` class first. If it doesn't find it there, it looks in the `Animal` class. This is a simple example of how inheritance and method overriding work.
class Animal:
def speak(self):
return "Generic animal sound"
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
mydog = Dog()
mycat = Cat()
print(mydog.speak())
print(mycat.speak())
Multiple Inheritance and MRO
This example demonstrates multiple inheritance. The `Derived` class inherits from both `Base1` and `Base2`. Both `Base1` and `Base2` have a `greet` method. The `mro()` method shows the order in which Python searches for methods. In this case, the MRO is `[
class Base1:
def greet(self):
return "Base1 greeting"
class Base2:
def greet(self):
return "Base2 greeting"
class Derived(Base1, Base2):
pass
# Accessing MRO
print(Derived.mro())
derived_object = Derived()
print(derived_object.greet()) # Calls Base1's greet method
Customizing MRO with `super()`
The `super()` function allows you to call methods from parent classes. In this example, each class's `__init__` method calls `super().__init__()`, which calls the `__init__` method of the next class in the MRO. The output demonstrates the order in which the `__init__` methods are called. The MRO is `[
class Base1:
def __init__(self):
print("Base1 init")
super().__init__()
class Base2:
def __init__(self):
print("Base2 init")
super().__init__()
class Derived(Base1, Base2):
def __init__(self):
print("Derived init")
super().__init__()
d = Derived()
print(Derived.mro())
Concepts Behind the Snippet
The core concepts behind this snippet are inheritance, multiple inheritance, method overriding, and the Method Resolution Order (MRO). Inheritance allows you to create new classes based on existing classes, inheriting their attributes and methods. Multiple inheritance allows a class to inherit from multiple base classes. Method overriding allows a subclass to provide a specific implementation of a method that is already defined in a parent class. The MRO determines the order in which base classes are searched when executing a method call.
Real-Life Use Case
Consider a GUI framework. You might have a `Button` class that inherits from `Widget` and `Clickable`. The `Widget` class handles basic drawing and positioning, while the `Clickable` class handles mouse clicks. The MRO would determine which class's methods are called if there were conflicts (e.g., if both `Widget` and `Clickable` defined a `handle_event` method). Understanding MRO is crucial for building complex, modular GUI systems.
Best Practices
When using multiple inheritance, be mindful of the MRO. Avoid complex inheritance hierarchies that can lead to ambiguous method calls. Use `super()` to ensure that methods are called in the correct order, especially when initializing objects. Document your inheritance hierarchies clearly to make it easier to understand the MRO.
Interview Tip
Be prepared to explain the concept of MRO and how it works in Python. You should be able to describe the C3 linearization algorithm (although you don't need to memorize the algorithm itself). Be able to give examples of how MRO can affect the behavior of your code.
When to Use Them
Use inheritance when you want to create a new class that is a specialized version of an existing class. Use multiple inheritance when you want to combine the functionality of multiple base classes into a single class. Use `super()` when you need to call methods from parent classes, especially when using multiple inheritance.
Memory Footprint
Inheritance itself does not significantly increase memory footprint. However, when creating objects of derived classes, keep in mind that these objects will contain data members from all their parent classes, potentially increasing memory usage compared to a single, monolithic class.
Alternatives
Instead of multiple inheritance, consider using composition. Composition involves creating classes that contain instances of other classes as members. This can often lead to more flexible and maintainable code, especially when dealing with complex relationships between classes.
Pros
Cons
FAQ
-
What is the Method Resolution Order (MRO)?
The Method Resolution Order (MRO) is the order in which Python searches for methods in a class hierarchy. It determines the order in which base classes are searched when a method is called on an instance of a class. Python uses the C3 linearization algorithm to determine the MRO. -
How can I see the MRO of a class?
You can use the `mro()` method of a class to see its MRO. For example, `MyClass.mro()` will return a list of classes in the order they are searched. -
What is the purpose of the `super()` function?
The `super()` function allows you to call methods from parent classes. It is particularly useful when using multiple inheritance, as it ensures that methods are called in the correct order according to the MRO. -
What happens if two parent classes define the same method?
The method that is called will be the one that appears first in the MRO. You can influence the MRO by the order in which you list the parent classes in the class definition (e.g., `class Derived(Base1, Base2)` vs. `class Derived(Base2, Base1)`). However, Python's MRO algorithm is more complex than simply left-to-right ordering, and it is generally best to understand and respect the calculated MRO.