What does 'super' do in Python? What is the difference between super().__init__() and explicit superclass __init__()?

Free Coding Questions Catalog
Boost your coding skills with our essential coding questions catalog. Take a step towards a better tech career now!

super in Python is a built-in function that provides access to methods in a superclass (parent class) from a child class. It is primarily used to call a method of the parent class within the child class, such as the constructor (__init__), or other methods that have been overridden.

Key Features of super:

  1. Avoids Hardcoding Parent Class Names: By dynamically resolving the parent class, super makes code more maintainable and less prone to errors.
  2. Supports Multiple Inheritance: It follows the Method Resolution Order (MRO) to determine which class’s method to call in cases of multiple inheritance.
  3. Allows Access to Overridden Methods: Lets you call methods in the parent class even when they are overridden in the child class.

Example:

class Parent: def __init__(self): print("Parent's __init__") class Child(Parent): def __init__(self): super().__init__() # Call the parent class's __init__ print("Child's __init__") child = Child()

Output:

Parent's __init__
Child's __init__

Difference Between super().__init__() and Explicit Parent.__init__()

1. super().__init__()

  • Description: Uses the super function to call the __init__ method of the parent class.
  • Key Advantage: It dynamically determines the class to call based on the Method Resolution Order (MRO), making it compatible with multiple inheritance scenarios.

Example:

class Parent: def __init__(self): print("Parent __init__") class Child(Parent): def __init__(self): super().__init__() # Uses super print("Child __init__") child = Child()

Output:

Parent __init__
Child __init__

2. Explicit Parent.__init__()

  • Description: Directly calls the parent class’s __init__ method using the class name.
  • Key Limitation: It bypasses the MRO, which can cause issues in multiple inheritance scenarios by calling the wrong method or causing redundant calls.

Example:

class Parent: def __init__(self): print("Parent __init__") class Child(Parent): def __init__(self): Parent.__init__(self) # Explicit call to Parent.__init__ print("Child __init__") child = Child()

Output:

Parent __init__
Child __init__

Differences in Behavior

1. Multiple Inheritance

  • super().__init__() works seamlessly in multiple inheritance by following the MRO.

Example:

class A: def __init__(self): print("A __init__") class B(A): def __init__(self): super().__init__() print("B __init__") class C(A): def __init__(self): super().__init__() print("C __init__") class D(B, C): def __init__(self): super().__init__() print("D __init__") d = D()

Output:

A __init__
C __init__
B __init__
D __init__

Explanation:

  • The MRO (D -> B -> C -> A) ensures that each class’s __init__ is called exactly once in the correct order.

  • Explicit Parent.__init__() in such cases can cause redundant or skipped calls, as it doesn't respect the MRO.

Example with Issues:

class A: def __init__(self): print("A __init__") class B(A): def __init__(self): A.__init__(self) print("B __init__") class C(A): def __init__(self): A.__init__(self) print("C __init__") class D(B, C): def __init__(self): B.__init__(self) C.__init__(self) print("D __init__") d = D()

Output:

A __init__
B __init__
A __init__
C __init__
D __init__

Problem:

  • A.__init__() is called twice because B and C both explicitly call it, leading to unexpected behavior.

2. Maintainability

  • Using super() makes the code more maintainable and less error-prone because the parent class name doesn't need to be hardcoded.
  • If the parent class changes, super() will still work correctly, while explicit calls like Parent.__init__() need to be updated manually.

When to Use Each Approach

ScenarioUse super().__init__()Use Explicit Parent.__init__()
Single InheritanceBoth work fine; super() is preferred for consistency.Acceptable but less preferred.
Multiple InheritanceUse super() to respect MRO and avoid redundant calls.Avoid explicit calls due to MRO issues.
Dynamic Parent Class Changessuper() adapts automatically.Requires manual updates if parent class changes.
Simpler Hierarchies (No Multiple Inheritance)super() is preferred for clarity.May be acceptable in small, simple hierarchies.

Summary

  • super().__init__():

    • Dynamically determines the parent class using the MRO.
    • Handles multiple inheritance correctly.
    • Makes code more maintainable and less error-prone.
  • Explicit Parent.__init__():

    • Directly calls the specified parent class's method.
    • Bypasses MRO, which can cause issues in multiple inheritance.
    • Less maintainable, as changes to the class hierarchy require manual updates.

In most cases, super() is the recommended approach for its flexibility, compatibility with multiple inheritance, and adherence to Python's design philosophy. Explicit calls should be reserved for specific scenarios where MRO behavior is not needed or desired.

TAGS
Coding Interview
CONTRIBUTOR
Design Gurus Team

GET YOUR FREE

Coding Questions Catalog

Design Gurus Newsletter - Latest from our Blog
Boost your coding skills with our essential coding questions catalog.
Take a step towards a better tech career now!
Explore Answers
Is it better to do a remote interview or in person interview?
Is it hard to study software engineering?
How many threads can be executed at a time?
Related Courses
Image
Grokking the Coding Interview: Patterns for Coding Questions
Grokking the Coding Interview Patterns in Java, Python, JS, C++, C#, and Go. The most comprehensive course with 476 Lessons.
Image
Grokking Data Structures & Algorithms for Coding Interviews
Unlock Coding Interview Success: Dive Deep into Data Structures and Algorithms.
Image
Grokking Advanced Coding Patterns for Interviews
Master advanced coding patterns for interviews: Unlock the key to acing MAANG-level coding questions.
Image
One-Stop Portal For Tech Interviews.
Copyright © 2024 Designgurus, Inc. All rights reserved.