methods
coding
python

Understanding Python super() with __init__() methods

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

super() is the standard way to continue method dispatch to the next class in Python's method resolution order, or MRO. In __init__() methods, it matters because defining a child initializer does not automatically call the parent initializer for you.

In simple inheritance, super() is the clean way to make sure the parent class does its setup. In multiple inheritance, it becomes even more important because it lets all participating classes cooperate instead of hard-coding one specific parent call.

The Basic Inheritance Case

If a subclass defines its own __init__(), Python does not automatically run the parent's __init__() unless you call it.

python
1class Parent:
2    def __init__(self, name):
3        self.name = name
4
5class Child(Parent):
6    def __init__(self, name, age):
7        super().__init__(name)
8        self.age = age
9
10child = Child("Alice", 10)
11print(child.name)
12print(child.age)

Without super().__init__(name), the Parent part of the object would never initialize name.

Why super() Is Better Than Naming the Parent Directly

You could write:

python
Parent.__init__(self, name)

That works in a trivial hierarchy, but it hard-codes the parent class into the child implementation. super() is better because it means "call the next implementation in the method resolution order," not "always call this exact class name forever."

That distinction matters when:

  • the hierarchy changes later
  • a mixin is added
  • multiple inheritance is involved
  • you want reusable cooperative class design

super() Follows the MRO, Not Just the Immediate Parent

This is the part many people miss. super() does not literally mean "parent." It means the next method in the class's MRO.

python
1class A:
2    pass
3
4class B(A):
5    pass
6
7class C(B):
8    pass
9
10print(C.mro())

The MRO tells Python which class comes next for method lookup, including super() calls.

So the right mental model is:

  • direct parent in simple cases
  • next class in MRO in general

Why This Matters in Multiple Inheritance

Multiple inheritance is where super() stops being a convenience and becomes the correct design tool.

python
1class A:
2    def __init__(self):
3        print("A")
4        super().__init__()
5
6class B:
7    def __init__(self):
8        print("B")
9        super().__init__()
10
11class C(A, B):
12    def __init__(self):
13        print("C")
14        super().__init__()
15
16C()
17print(C.mro())

Each class calls super(), so each initializer runs once in MRO order. That is called cooperative multiple inheritance.

If one class breaks the chain by not calling super(), later initializers may never run.

Forwarding Arguments with **kwargs

In cooperative hierarchies, a common pattern is for each class to consume the arguments it needs and pass the rest onward.

python
1class Named:
2    def __init__(self, *, name, **kwargs):
3        self.name = name
4        super().__init__(**kwargs)
5
6class Aged:
7    def __init__(self, *, age, **kwargs):
8        self.age = age
9        super().__init__(**kwargs)
10
11class Person(Named, Aged):
12    def __init__(self, *, name, age):
13        super().__init__(name=name, age=age)
14
15p = Person(name="Alice", age=10)
16print(p.name, p.age)

This pattern is common in frameworks and mixin-heavy code because it lets classes cooperate without knowing every detail about sibling classes.

When You Might Not Need super()

If a class does not need to customize initialization at all, you may not need to define __init__() in the subclass. And if a one-off class hierarchy is extremely simple, direct parent calls may appear to work.

But if the class is meant to be reusable or if multiple inheritance is even a possibility, super() is the safer default.

Common Pitfalls

The biggest mistake is thinking super() literally means "my immediate parent." Another is calling a parent class directly in a multiple-inheritance hierarchy, which can duplicate or skip initialization. Developers also often forget to use super() consistently across all participating classes, which breaks cooperative initialization. Finally, poorly coordinated constructor signatures can make argument forwarding difficult if classes do not agree on how to consume and pass along parameters.

Summary

  • 'super() in __init__() continues initialization through the MRO.'
  • It is useful in simple inheritance and essential in cooperative multiple inheritance.
  • 'super() is better than hard-coding parent class names.'
  • '**kwargs forwarding is a common pattern in reusable cooperative hierarchies.'
  • Think of super() as "next in MRO," not just "parent."

Course illustration
Course illustration

All Rights Reserved.