In Python, when working with multiple inheritance, understanding how the super()
function works is crucial. The super()
function allows you to call methods from parent classes, but its behavior can be complex in cases of multiple inheritance.
To start, let’s define a simple example of multiple inheritance:
class First(object):
def __init__(self):
print("First(): entering")
super(First, self).__init__()
print("First(): exiting")
class Second(object):
def __init__(self):
print("Second(): entering")
super(Second, self).__init__()
print("Second(): exiting")
class Third(First, Second):
def __init__(self):
print("Third(): entering")
super(Third, self).__init__()
print("Third(): exiting")
When you instantiate Third()
, Python’s Method Resolution Order (MRO) algorithm determines the order in which methods from parent classes are called. The MRO is calculated based on a depth-first left-to-right traversal of the inheritance hierarchy.
To understand how this works, let’s break down what happens when we call Third()
:
- According to the MRO,
Third.__init__
executes.- It prints "Third(): entering".
- Then
super(Third, self).__init__()
executes and returnsFirst.__init__
, which is called.
First.__init__
executes.- It prints "First(): entering".
- Then
super(First, self).__init__()
executes and returnsSecond.__init__
, which is called.
Second.__init__
executes.- It prints "Second(): entering".
- Then
super(Second, self).__init__()
executes and returnsobject.__init__
, which is called.
object.__init__
executes (no print statements).- Execution goes back to
Second.__init__
, which then prints "Second(): exiting". - Execution goes back to
First.__init__
, which then prints "First(): exiting". - Finally, execution goes back to
Third.__init__
, which then prints "Third(): exiting".
The output of instantiating Third()
will be:
Third(): entering
First(): entering
Second(): entering
Second(): exiting
First(): exiting
Third(): exiting
As you can see, the MRO algorithm ensures that methods from parent classes are called in a specific order. The super()
function plays a crucial role in this process by allowing you to call methods from parent classes.
It’s worth noting that if Python cannot find a coherent method resolution order (i.e., there is ambiguity), it will raise an exception instead of falling back to behavior that might surprise the user.
To illustrate this, let’s consider another example:
class First(object):
def __init__(self):
print("First(): entering")
super(First, self).__init__()
print("First(): exiting")
class Second(First):
def __init__(self):
print("Second(): entering")
super(Second, self).__init__()
print("Second(): exiting")
class Third(First, Second):
def __init__(self):
print("Third(): entering")
super(Third, self).__init__()
print("Third(): exiting")
In this case, Python will raise a TypeError
because it cannot determine the method resolution order:
TypeError: Cannot create a consistent method resolution order (MRO) for bases Second, First
To avoid such issues, you should ensure that your inheritance hierarchy is well-structured and does not introduce ambiguity.
In summary, understanding how Python’s super()
function works with multiple inheritance requires knowledge of the Method Resolution Order algorithm. By following the examples in this tutorial, you can gain a deeper insight into how to use super()
effectively in complex inheritance scenarios.