Skip to main content

Python Inheritance: super() and Derived Classes

Inheritance is a cornerstone of object-oriented programming that allows you to create a hierarchy of classes where derived (child) classes inherit attributes and methods from base (parent) classes. Rather than duplicating code across similar classes like Dog, Cat, and Fish, you define a shared Animal parent class and have each child class inherit its common behavior. The super() function is essential for calling parent class methods from child classes, especially when initializing attributes in a derived class.


Understanding the "Is-A" Relationship in Inheritance​

Inheritance models an "is-a" relationship between classes. This relationship indicates that a child class is a specialized version of its parent:

  • A Dog is an Animal
  • A Car is a Vehicle
  • A SavingsAccount is a type of BankAccount

This relationship means the child class automatically receives all the functionality of the parent class and can then add its own unique features or modify existing ones. The parent class defines shared behavior; the child class specializes it.

The Syntax: To make a class inherit from another, place the parent class's name in parentheses after the child class's name:

class Parent:
pass

class Child(Parent): # Child inherits from Parent
pass

Inheritance reduces code duplication and creates logical hierarchies that match real-world relationships, making your code more maintainable and intuitive.


Creating Derived Classes: The Animal and Dog Example​

Let's build a concrete example showing inheritance in action. We'll create an Animal base class and then a Dog derived class that specializes it.

# inheritance_example.py

class Animal:
def __init__(self, name: str, age: int):
print("Animal __init__ called")
self.name = name
self.age = age

def speak(self):
# Generic implementation for any animal
return "Some generic animal sound"

def display(self):
print(f"I am an animal named {self.name}, and I am {self.age} years old.")

Now, let's create a Dog class that inherits from Animal. A dog is an animal, but it also has a breed attribute and makes a specific sound:

class Dog(Animal):
def __init__(self, name: str, age: int, breed: str):
print("Dog __init__ called")
# How do we initialize the name and age from the parent?
# We use super()!
super().__init__(name, age)
self.breed = breed # This is a Dog-specific attribute

# This is method overriding
def speak(self):
return "Woof!"

Notice that the Dog class defines its own __init__ method. Inside it, we call super().__init__(name, age) to initialize the parent class's attributes. This pattern is crucial for proper initialization in inheritance hierarchies and prevents code duplication.


The super() Function: Accessing Parent Class Methods​

The super() function returns a proxy object that allows you to access methods and attributes of the parent class. It's most commonly used to call the parent's __init__ method when a child class has its own initialization logic.

In the Dog example above, super().__init__(name, age) means: "Call the __init__ method of my parent class (Animal) and pass it the name and age arguments."

Why use super()?

  • Code Reusability: Don't duplicate parent class initialization code in child classes. Call it once with super().
  • Maintainability: If you ever modify the Animal's __init__ to add a new attribute, all child classes using super() automatically inherit the change.
  • Multiple Inheritance Support: super() correctly handles complex inheritance chains and multiple inheritance scenarios.
  • Explicit Intent: super() makes it clear that you're calling parent functionality, not reinventing it.

According to Python's method resolution order (MRO) documentation, super() uses Python's MRO to determine which parent method to call, enabling correct behavior even in complex inheritance structures.

# Example: Using super() correctly
class Parent:
def greet(self):
return "Hello from Parent"

class Child(Parent):
def greet(self):
# Call parent's greet() and extend it
parent_greeting = super().greet()
return f"{parent_greeting}, and Child"

child = Child()
print(child.greet()) # Output: Hello from Parent, and Child

This pattern of extending parent behavior is more flexible than completely overriding it.


Method Overriding: Specializing Parent Behavior​

When a child class defines a method with the same name as a method in its parent class, it's called method overriding. This allows the child class to provide a more specific implementation suited to its type.

In the Dog and Animal example, both classes have a speak() method:

  • Animal.speak() returns a generic sound
  • Dog.speak() returns "Woof!"

When you call speak() on a Dog object, Python uses the Dog version, not the Animal version. This is polymorphism in action—the same method name behaves differently depending on the object's type.

# --- Using inheritance in practice ---

# Create an instance of the child class
my_dog = Dog("Buddy", 4, "Golden Retriever")

# The 'display' method was inherited directly from Animal
my_dog.display()

# The 'speak' method was overridden by the Dog class
sound = my_dog.speak()
print(f"{my_dog.name} says: {sound}")

# The 'breed' attribute is specific to the Dog class
print(f"{my_dog.name} is a {my_dog.breed}.")

Output:

Dog __init__ called
Animal __init__ called
I am an animal named Buddy, and I am 4 years old.
Buddy says: Woof!
Buddy is a Golden Retriever.

This example perfectly illustrates the power of inheritance. The Dog class received the display() method for free from Animal, provided its own specialized version of speak(), and added its own unique attribute (breed). All without duplicating any code.


Key Takeaways​

  • Inheritance models "is-a" relationships: A child class inherits attributes and methods from its parent, specializing them for its specific type.
  • Syntax: Create a subclass with class Child(Parent): to inherit from a parent class.
  • Use super(): Call parent class methods (especially __init__) with super() to avoid code duplication and enable proper initialization.
  • Method Overriding: Child classes can provide their own implementation of parent methods, enabling polymorphism.
  • Reduces Duplication: Inheritance eliminates copying common code across similar classes, making your codebase more maintainable.

Frequently Asked Questions​

Can a class inherit from multiple parents in Python?​

Yes, Python supports multiple inheritance. A class can inherit from multiple parent classes: class Child(Parent1, Parent2):. However, multiple inheritance is complex and can lead to the "diamond problem" where method resolution becomes ambiguous. Use composition (one class containing instances of other classes) instead of multiple inheritance when possible, unless you have a clear, simple hierarchy.

What happens if I forget to call super().__init__() in a child class?​

The parent class's __init__ method won't execute, and parent attributes won't be initialized. This causes AttributeError when your code tries to access inherited attributes. Always call super().__init__() in a child's __init__ to ensure parent initialization happens first, unless you intentionally want to skip it.

Can I call super() outside of __init__?​

Yes, you can use super() in any method to access parent functionality. For example, a child's process() method can call super().process() to execute parent logic and then add child-specific behavior. This extends parent functionality rather than completely replacing it.

What is the method resolution order (MRO)?​

MRO is Python's algorithm for determining which method to call in an inheritance hierarchy. Use ClassName.__mro__ or ClassName.mro() to see the order. For simple single inheritance, it's straightforward: child methods are checked before parent methods. For multiple inheritance, MRO prevents ambiguity and ensures super() calls the correct parent method.


Further Reading​


Next Steps​

Inheritance is one of the major pillars of advanced OOP. The next logical concept is Polymorphism, which allows you to treat objects of different classes in the same way, creating flexible and extensible code. We'll explore this in our next article.

Happy coding!