Concepts / Inheritance and Class Extension

Inheritance and Class Extension

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.

  • Programming

One Instance, Two Initializers

When a child class extends a parent class, the child instance can contain attributes initialized by both classes. The child class adds its own setup, but the parent class's setup does not happen automatically inside the child's __init__ method. The child initializer must use super().__init__() to call the parent initializer.

inherits and extendsParent classattributes and methodsChild classinherited and added members
What does the child class inherit from the parent, and what does it add?

The Delegation Path

class Account: def __init__(self, owner): self.owner = owner class SavingsAccount(Account): def __init__(self, owner, interest_rate): super().__init__(owner) self.interest_rate = interest_rate

super().__init__(owner)returns controlSavingsAccount.__init__child setup beginsAccount.__init__owner is initializedSavingsAccount.__init__interest_rate isinitialized
How does control move from the child initializer to the parent initializer and then back to the child?

Creation Order

The initialization order is deliberate. First, the child class's __init__ method begins. Next, super().__init__() calls the parent class's initialization method with the correct arguments. The parent initializer sets the parent attributes. Finally, execution returns to the child initializer, which sets the child-specific attributes. Calling super().__init__() at the beginning of the child initializer keeps this order explicit and ensures complete instance setup.

startssuper().__init__()returnsChild instancecreation requestedChild __init__beginsParent __init__parent attributesChild __init__child attributes
What happens first, next, and last when both parent and child initializers run?

Tracing a SavingsAccount

Determine which attributes are initialized when a SavingsAccount is created.

Child initialization starts: The SavingsAccount initializer receives owner and interest_rate.

Parent initialization runs: super().__init__(owner) calls Account.__init__, which sets the owner attribute.

Child initialization resumes: After the parent initializer returns, the child sets interest_rate.

The resulting child instance contains the parent attribute owner and the child attribute interest_rate.

Combined Instance State

A child class instance inherits the parent class's attributes and methods and adds its own. In the generated example, owner comes from the parent initializer and interest_rate comes from the child initializer. These attributes coexist in the same child instance; they are not separate objects created by the two classes.

containscontainsSavingsAccountinstanceone instanceownerparent attributeinterest_ratechild attribute
How can one child instance contain attributes initialized by both the parent and child classes?

Place super().__init__() at the beginning of the child class's __init__ method. Pass the arguments required by the parent initializer. This allows the parent attributes to be initialized before the child-specific attributes are set.

When the Delegation Is Missing

  • Omitting super().__init__() from the child initializer.

    The parent attributes are not initialized by the parent initializer.

    Fix: Call super().__init__() at the beginning of the child initializer.

  • Calling super().__init__() without the required parent arguments.

    The parent initializer needs the correct arguments to initialize its attributes.

    Fix: Pass the arguments required by the parent initializer.

  • Assuming that child-specific setup replaces parent setup.

    A child instance inherits parent attributes and methods as well as adding its own.

    Fix: Use super().__init__() so both parent and child initialization take place.

containscontainscontainsSavingsAccountchild attribute onlyinterest_rateinitializedSavingsAccountparent and child attributesownerinitialized by parentinterest_rateinitialized by child
What changes in the resulting object when the child initializer calls super().__init__() versus when it omits that call?

Checking Inherited Members

A child class inherits all attributes and methods from its parent class and adds its own. The source pack identifies dir() as one way to verify the members available through the child class. Use it as an inspection tool when you want to examine what the child class provides through inheritance and extension.

python

In this example, the parent initializer supplies owner, while the child initializer supplies interest_rate. The call to dir(account) can be used to inspect the attributes and methods available through the resulting child instance.

Practice the Trace

MEDIUM

Create a parent class named Device with an __init__ method that initializes model. Then create a child class named Phone whose __init__ method accepts model and operating_system. Use super().__init__(model) before initializing operating_system. Finally, describe the order in which the two initializers run and list the attributes in one Phone instance.

Hints
  • The parent initializer must receive the model argument.
  • Place super().__init__(model) at the beginning of Phone.__init__.
  • The completed instance should contain one parent attribute and one child attribute.
  1. Identify the parent class and the child class.
  2. Find the child initializer's super().__init__() call.
  3. Check that the arguments passed to super().__init__() match the parent initializer's needs.
  4. Trace the parent attribute initialization before the child attribute initialization.
  5. Confirm that both sets of attributes belong to the one child instance.

Key Takeaways

  1. super() calls a method from the parent class.
  2. super().__init__() runs the parent initialization method from the child initializer.
  3. The parent initializer should run before child-specific attributes are set.
  4. A child instance can contain both parent attributes and child attributes.
  5. dir() can be used to inspect attributes and methods available through the child instance.

Key Takeaways

  • super() provides the delegation from a child class to its parent class.
  • super().__init__() ensures that parent attributes are initialized before child-specific attributes.
  • A child instance combines the attributes and methods inherited from the parent with the additions made by the child.
  • The safest initialization pattern is to call super().__init__() at the beginning of the child initializer with the correct arguments.