Chain-calling parent initialisers in python
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Python, chain-calling parent initializers is done with super().__init__(). This calls the parent class's __init__ method, ensuring proper initialization up the inheritance chain. For single inheritance, super() calls the direct parent. For multiple inheritance, super() follows the Method Resolution Order (MRO), which ensures each class in the hierarchy is initialized exactly once. Always use super() instead of calling parent classes by name to maintain correct MRO behavior.
Basic super().init()
super().__init__(name) calls the parent Animal.__init__, passing name. The child class then sets its own attributes.
Multi-Level Inheritance
Each super().__init__() call chains up to the next parent, all the way to the top of the hierarchy.
Multiple Inheritance and MRO
With multiple inheritance, super() follows the Method Resolution Order (MRO):
super() in D calls B.__init__, which calls C.__init__ (not A.__init__), which then calls A.__init__. The MRO ensures A.__init__ is called only once, even though both B and C inherit from A.
Using **kwargs for Cooperative Multiple Inheritance
When classes in a multiple inheritance hierarchy have different __init__ parameters, use **kwargs to pass arguments through the chain:
Each class extracts its own parameters and passes the rest via **kwargs. This is the cooperative multiple inheritance pattern.
Calling Specific Parent (Not Recommended)
You can call a parent class by name instead of using super():
This works for single inheritance but breaks with multiple inheritance because it bypasses the MRO and can cause parent classes to be initialized multiple times or not at all.
The Diamond Problem
Using super() throughout avoids the diamond problem by following the MRO.
Python 2 vs Python 3
Python 3's super() with no arguments is syntactic sugar that automatically determines the correct class and instance.
Skipping a Parent's init
Sometimes you want to skip the immediate parent and call a grandparent:
This is generally discouraged because it breaks the initialization chain and may leave the object in an inconsistent state.
Common Pitfalls
- Forgetting to call
super().__init__(): If a child class does not callsuper().__init__(), the parent's attributes are never set. The child instance will be missing parent attributes, causingAttributeErrorlater. - Calling parent by name in multiple inheritance:
ParentClass.__init__(self, ...)bypasses the MRO and causes the diamond problem — a shared ancestor may be initialized multiple times. Always usesuper()in multiple inheritance hierarchies. - Mismatched init signatures: If
Parent.__init__takes(self, x)andChild.__init__takes(self, x, y), you must correctly passxtosuper().__init__(x). Forgetting to pass required arguments causesTypeError. - Order of super() call matters: Calling
super().__init__()at the beginning vs end of__init__affects when parent attributes are set. If child code depends on parent attributes, callsuper()first. If parent depends on child attributes, callsuper()last (rare). - **Not using kwargs in cooperative inheritance: Without
**kwargs, classes in a multiple inheritance chain cannot pass unknown arguments through to other parents. Each class should accept and forward**kwargsfor cooperative behavior.
Summary
- Use
super().__init__()to call parent initializers in Python 3 super()follows the Method Resolution Order (MRO), ensuring each class is initialized once- For multiple inheritance, use the
**kwargspattern for cooperative initialization - Avoid calling parent classes by name (
Parent.__init__(self)) — it bypasses MRO - Check the MRO with
ClassName.__mro__orClassName.mro()when debugging initialization order

