100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

Inheritance

How single inheritance, `super().__init__()`, and method overriding let subclasses reuse and specialize parent class behavior.

Object-Oriented Programming FundamentalsIntermediate10 min readJul 8, 2026
Analogies

Introduction

Inheritance lets a new class, called a subclass or child class, derive attributes and methods from an existing class, called a superclass or parent class. This models 'is-a' relationships and enables code reuse: instead of rewriting shared behavior, a subclass extends the parent and adds or modifies only what makes it different. Python supports single inheritance (one direct parent, the focus of this lesson) as well as multiple inheritance, but the core mechanics are best understood through the single-inheritance case first.

🏏

Cricket analogy: A T20 format 'is-a' cricket match, inheriting the core rules of bowling and batting from the general game while adding its own specific overs-limit and powerplay rules on top.

Explanation

A subclass is declared by listing the parent class in parentheses: class Dog(Animal):. Inside the subclass's __init__, calling super().__init__(...) invokes the parent class's constructor, letting the subclass reuse the parent's initialization logic instead of duplicating it, while still adding its own subclass-specific attributes afterward. Method overriding occurs when a subclass defines a method with the same name as one in its parent, replacing the parent's implementation for instances of the subclass; the subclass method can still call the parent's version explicitly via super().method_name() if it wants to extend rather than fully replace the behavior. It is important to distinguish overriding from overloading: overloading means defining multiple methods with the same name but different parameter signatures (different number or type of arguments) within the same class, and Python does not support true overloading — if you define two methods with the same name in one class, the second definition simply replaces the first. Python instead achieves overloading-like flexibility through default argument values, *args/**kwargs, or the functools.singledispatch decorator, but that is a distinct mechanism from what languages like Java call method overloading.

🏏

Cricket analogy: A young all-rounder joining the national team calls on the senior coach's foundational batting drills (super().__init__) before adding their own signature bowling variation; if they bat exactly like a specialist opener but with an extra reverse-sweep, that's overriding, not overloading, since you can't have two 'bat()' methods with different argument counts on the same player.

Example

python
class Animal:
    def __init__(self, name, sound="..."):
        self.name = name
        self.sound = sound

    def speak(self):
        return f"{self.name} says {self.sound}"

    def describe(self):
        return f"I am an animal named {self.name}"


class Dog(Animal):  # single inheritance: Dog derives from Animal
    def __init__(self, name, breed):
        super().__init__(name, sound="Woof")  # reuse parent constructor
        self.breed = breed

    def speak(self):  # method overriding: replaces Animal.speak
        base = super().speak()  # still calls the parent's version
        return f"{base} (a {self.breed})"


generic = Animal("Creature")
rex = Dog("Rex", "Labrador")

print(generic.speak())   # Creature says ...
print(rex.speak())       # Rex says Woof (a Labrador)
print(rex.describe())    # Inherited unchanged from Animal
print(isinstance(rex, Animal))  # True -- Dog is-a Animal

Analysis

Dog(Animal) establishes single inheritance: Dog has exactly one direct parent, Animal. Inside Dog.__init__, super().__init__(name, sound="Woof") calls Animal.__init__, so self.name and self.sound are set using the parent's logic; Dog then adds its own self.breed afterward, avoiding duplication of the name/sound assignment logic. Dog.speak is an override: it has the same name and signature as Animal.speak, but a completely different body, and Python resolves rex.speak() to Dog.speak because Dog is the more specific (derived) type. Notice Dog.speak calls super().speak() internally, so it extends rather than fully discards the parent's behavior. describe() is not overridden in Dog, so rex.describe() falls back to Animal.describe, demonstrating inherited (unchanged) behavior. Finally, this example could not demonstrate method overloading, because Python does not support it: defining speak twice in the same class with different parameters would simply mean the later definition silently replaces the earlier one, not that Python dispatches based on argument count or type.

🏏

Cricket analogy: Virat Kohli's technique inherits from general batting fundamentals but overrides the follow-through with his own signature style; when commentators call for 'technique', the more specific Kohli style is what's used, not the generic textbook version, and his unchanged running-between-wickets habit falls back to the general coaching manual.

Key Takeaways

  • Single inheritance means a subclass derives from exactly one direct parent class.
  • super().__init__() calls the parent's constructor so the subclass can reuse its initialization logic.
  • Method overriding replaces a parent's method implementation in the subclass; super().method() can still invoke the parent's version.
  • Python does not support true method overloading — defining the same method name twice in one class just overwrites the first definition.

Practice what you learned

Was this page helpful?

Topics covered

#Python#SoftwareEngineeringStudyNotes#SoftwareEngineering#Inheritance#Explanation#Example#Analysis#Key#OOP#StudyNotes#SkillVeris