Python's Super Function with Multiple Inheritance

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():

  1. According to the MRO, Third.__init__ executes.
    • It prints "Third(): entering".
    • Then super(Third, self).__init__() executes and returns First.__init__, which is called.
  2. First.__init__ executes.
    • It prints "First(): entering".
    • Then super(First, self).__init__() executes and returns Second.__init__, which is called.
  3. Second.__init__ executes.
    • It prints "Second(): entering".
    • Then super(Second, self).__init__() executes and returns object.__init__, which is called.
  4. object.__init__ executes (no print statements).
  5. Execution goes back to Second.__init__, which then prints "Second(): exiting".
  6. Execution goes back to First.__init__, which then prints "First(): exiting".
  7. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *