Understanding __init__ and the Constructor
super() is a special syntax that calls a method from the parent class. In the context of __init__, super().__init__() ensures the parent class's initialization runs before the child class's initialization.
The Initialization Handoff
When a child class provides its own __init__ method, it takes responsibility for the child-specific initialization process. The parent class may still have initialization work to perform. super().__init__() provides the handoff: it calls the parent class's initialization method so the parent attributes are initialized before the child-specific attributes are set.
What do you think happens?
A child class creates an instance and its __init__ method calls super().__init__(). Which initialization runs first?
Reveal answer
Answer: The parent initialization runs first, followed by the child-specific initialization.
In this context, super().__init__() calls the parent class's __init__ method. The child continues with its own attribute setup after that call returns.
What super() Calls
super() is special syntax that calls a method from the parent class. When it is followed by __init__(), super().__init__() calls the parent class's initialization method.
The name __init__ identifies the initialization method used by a class. A child class can define its own __init__ method to add child-specific setup, but that does not remove the parent class's initialization responsibility. Calling super().__init__() lets the child initialization method use the parent initialization method as part of the same setup process.
A Complete Initialization Trace
class Parent: def __init__(self, name): self.name = name class Child(Parent): def __init__(self, name, level): super().__init__(name) self.level = level item = Child("Ari", 3)
item.name
# "Ari"
item.level
# 3This example shows the execution order rather than two separate objects being assembled independently. The child instance contains the attribute initialized by the parent and the attribute initialized by the child. The parent and child initialization responsibilities therefore coexist in one child instance.
Skipping the Parent Setup
Defining a child __init__ method but never calling super().__init__().
The parent initialization is skipped, so the parent-defined attribute is not initialized by that method.
Fix:
Call super().__init__() in the child __init__ method before setting child-specific attributes.Calling super().__init__() with the wrong or missing arguments.
The parent initialization must receive the correct arguments to initialize parent attributes.
Fix:
Pass the arguments required by the parent initialization method.Setting child-specific attributes before calling the parent initialization.
The recommended initialization order is for the parent initialization to run before child-specific attributes are set.
Fix:
Place super().__init__() at the beginning of the child __init__ method.
Responsibilities Across the Class Relationship
| Part of the design | Initialization responsibility | Result in the child instance |
|---|---|---|
| Parent class | Initializes parent-defined attributes when its __init__ method runs | Parent attributes are available on the child instance |
| Child class | Adds child-specific initialization after calling super().__init__() | Child attributes are added to the same instance |
| super().__init__() | Connects the child initialization method to the parent initialization method | Parent setup occurs before child-specific setup |
A child class instance inherits the parent's attributes and methods and adds its own. The built-in dir() function can be used to inspect the names available on the instance, including inherited and child-provided members. The important point is that inheritance does not make the parent attributes disappear when child attributes are added; both sets can be part of the child instance.
Practice the Execution Order
Consider a Parent class whose __init__ method initializes a parent attribute, and a Child class whose __init__ method calls super().__init__() before initializing a child attribute. Write the execution order in four steps, beginning with creation of the Child instance and ending with the completed child-specific setup.
Hints
- Start with Child.__init__.
- Place the parent initialization immediately after the super().__init__() call.
- The child-specific attribute is set after the parent initialization returns.
Tracing the Handoff
A child instance is created using a child __init__ method that calls super().__init__() and then sets a child-specific attribute. What happens in order?
Step 1: The child instance creation enters the child class's __init__ method.
Step 2: The child method executes super().__init__(), which calls the parent class's initialization method.
Step 3: The parent initialization sets the parent-defined attributes using the arguments passed to it.
Step 4: Control returns to the child method, which sets the child-specific attributes.
The completed child instance contains both the attributes initialized by the parent and the attributes initialized by the child.
Key Takeaways
- super() calls a method from the parent class.
- super().__init__() calls the parent class's initialization method.
- The parent initialization should run before child-specific attributes are set.
- The correct arguments must be passed to the parent initialization.
- A child instance can contain both parent-defined and child-defined attributes.
Key Takeaways
- super() connects a child class method to a parent class method.
- super().__init__() ensures that parent initialization runs before child-specific initialization.
- The parent and child attributes can coexist in the same child instance.
- Always pass the correct arguments and call super().__init__() at the beginning of the child __init__ method.