How to Use super() in Python: Inheritance and Method Resolution Simplified

Tarun SharmaTarun Sharma
5 min read

Introduction

In Python, the super() function is an essential tool when working with object-oriented programming (OOP). It allows you to call methods from a parent class within a child class, which can be particularly useful in complex inheritance hierarchies. This article will guide you through the concept of super(), why it’s useful, and how to effectively use it in your code.

What is super()?

The super() function returns a temporary object of the superclass that allows you to call its methods. In simple terms, super() enables you to access methods and properties from a parent class, without needing to know the parent class's name. This is particularly useful when a child class overrides a method from the parent class but still wants to use the functionality provided by the parent class.

Why Use super()?

Using super() provides several benefits:

  • Code Reusability: Allows you to reuse the code from parent classes without rewriting it in the child class.

  • Maintainability: Makes your code easier to maintain and extend. If the parent class changes, those changes automatically reflect in child classes that use super().

  • Multiple Inheritance: Helps ensure that methods are called in the correct order (following the Method Resolution Order, or MRO) when dealing with multiple inheritance.

Basic Usage of super()

Let’s start with a simple example to demonstrate the basic usage of super() in a single inheritance scenario.

Example 1: Initializing Parent Class Attributes

Without super()

class Parent:
    def __init__(self, name):
        self.name = name
        print(f"Parent initialized with name: {self.name}")

class Child(Parent):
    def __init__(self, name, age):
        Parent.__init__(self, name)  # Directly calling the parent class's __init__ method
        self.age = age
        print(f"Child initialized with name: {self.name} and age: {self.age}")

child = Child("Alice", 10)

Output:

Parent initialized with name: Alice
Child initialized with name: Alice and age: 10

With super()

class Parent:
    def __init__(self, name):
        self.name = name
        print(f"Parent initialized with name: {self.name}")

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)  # Using super() to call the parent class's __init__ method
        self.age = age
        print(f"Child initialized with name: {self.name} and age: {self.age}")

child = Child("Alice", 10)

Output:

Parent initialized with name: Alice
Child initialized with name: Alice and age: 10

Explanation: In both examples, the Parent class's __init__ method initializes the name attribute. However, using super() is more flexible and easier to maintain because it automatically adapts to changes in the class hierarchy.

Overriding Methods with super()

When a child class overrides a method from the parent class, super() allows the child class to extend or modify the parent class’s behavior rather than replacing it entirely.

Example 2: Overriding Methods

Without super()

class Parent:
    def speak(self):
        print("Parent speaking")

class Child(Parent):
    def speak(self):
        print("Child speaking")  # This overrides the Parent's speak method entirely

child = Child()
child.speak()

Output:

Child speaking

With super()

class Parent:
    def speak(self):
        print("Parent speaking")

class Child(Parent):
    def speak(self):
        super().speak()  # Calls the Parent's speak method
        print("Child speaking")

child = Child()
child.speak()

Output:

Parent speaking
Child speaking

Explanation: In the first example, the Child class completely overrides the speak method, so the Parent class’s speak method is never called. In the second example, super().speak() is used to call the Parent class’s speak method, allowing the Child class to build upon the parent’s behavior rather than replacing it.

Using super() in Multiple Inheritance

In Python, a class can inherit from multiple parent classes. super() plays a crucial role in multiple inheritance by ensuring that methods are called in the correct order, known as the Method Resolution Order (MRO).

Example 3: Multiple Inheritance

Without super()

class A:
    def action(self):
        print("Action in A")

class B(A):
    def action(self):
        print("Action in B")
        A.action(self)  # Manually calling the method from A

class C(A):
    def action(self):
        print("Action in C")
        A.action(self)  # Manually calling the method from A

class D(B, C):
    def action(self):
        print("Action in D")
        B.action(self)  # Manually calling the method from B
        C.action(self)  # Manually calling the method from C

d = D()
d.action()

Output:

Action in D
Action in B
Action in A
Action in C
Action in A

With super()

class A:
    def action(self):
        print("Action in A")

class B(A):
    def action(self):
        print("Action in B")
        super().action()  # Using super() to call the next class's action method

class C(A):
    def action(self):
        print("Action in C")
        super().action()  # Using super() to call the next class's action method

class D(B, C):
    def action(self):
        print("Action in D")
        super().action()  # Using super() to call the next class's action method

d = D()
d.action()

Output:

Action in D
Action in B
Action in C
Action in A

Explanation: Using super() in the context of multiple inheritance ensures that each method is called in the correct order and only once, following the MRO. This avoids issues like duplicate method calls that can occur when manually calling parent methods.

Best Practices for Using super()

  • Always use super() instead of directly calling parent methods: This makes your code more flexible, maintainable, and easier to extend, especially in complex inheritance structures.

  • Understand the MRO: When using multiple inheritance, it’s crucial to understand the Method Resolution Order to predict how super() will resolve method calls. You can inspect the MRO using ClassName.mro() or ClassName.__mro__.

  • Use super() in constructors (__init__): This is a common practice to ensure that parent class attributes are properly initialized.

Conclusion

The super() function is an indispensable tool in Python, especially when working with inheritance. It promotes code reuse, maintainability, and helps manage complex class hierarchies with ease. By using super(), you can create flexible and robust code that adapts well to changes and extensions.

Whether you are working with single inheritance or complex multiple inheritance, mastering super() will significantly improve the quality and readability of your code.


0
Subscribe to my newsletter

Read articles from Tarun Sharma directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Tarun Sharma
Tarun Sharma

Hi there! I’m Tarun, a Senior Software Engineer with a passion for technology and coding. With experience in Python, Java, and various backend development practices, I’ve spent years honing my skills and working on exciting projects. On this blog, you’ll find insights, tips, and tutorials on topics ranging from object-oriented programming to tech trends and interview prep. My goal is to share valuable knowledge and practical advice to help fellow developers grow and succeed. When I’m not coding, you can find me exploring new tech trends, working on personal projects, or enjoying a good cup of coffee. Thanks for stopping by, and I hope you find my content helpful!