⚡IntermediateObject-Oriented Python

Inheritance and Polymorphism

Building class hierarchies with inheritance, super(), and polymorphic behaviour.

Overview

Inheritance lets you create a new class (child/subclass) that automatically gets all the attributes and methods of an existing class (parent/superclass). You extend or override only what's different, avoiding repetition. Polymorphism means different classes can implement the same method name, and the correct version is called automatically based on the actual type of the object. Code that calls `animal.speak()` works whether `animal` is a Dog, Cat, or Bird each class provides its own `speak()` implementation. `super()` gives you access to the parent class, most commonly used in `__init__` to run the parent's constructor before adding child-specific setup: `super().__init__(...)`. Python also supports multiple inheritance a class can inherit from more than one parent. Python uses the C3 linearisation algorithm (MRO Method Resolution Order) to determine which parent's method is called when there's ambiguity.

Key Points

  • •`class Child(Parent):` Child inherits all attributes and methods from Parent
  • •`super().__init__(...)` call the parent constructor from the child
  • •Override a method by defining it with the same name in the child class
  • •`isinstance(obj, Class)` True if obj is an instance of Class or any subclass
  • •`issubclass(Child, Parent)` True if Child inherits from Parent
  • •Polymorphism: the same method name behaves differently depending on the object's type
  • •MRO (`ClassName.__mro__`) shows the order Python searches for methods

Examples

Basic inheritance with super()

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

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

    def __str__(self):
        return f"{self.__class__.__name__}({self.name})"

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name, "Woof")   # reuse parent __init__

    def fetch(self):
        return f"{self.name} fetches the ball!"

class Cat(Animal):
    def __init__(self, name):
        super().__init__(name, "Meow")

rex = Dog("Rex")
whiskers = Cat("Whiskers")
print(rex.speak())     # Rex says Woof!
print(whiskers.speak()) # Whiskers says Meow!
print(rex.fetch())     # Rex fetches the ball!

Polymorphism same interface, different behaviour

class Shape:
    def area(self):
        raise NotImplementedError("Subclass must implement area()")

class Rectangle(Shape):
    def __init__(self, w, h):
        self.w, self.h = w, h
    def area(self):
        return self.w * self.h

class Circle(Shape):
    def __init__(self, r):
        self.r = r
    def area(self):
        return 3.14159 * self.r ** 2

shapes = [Rectangle(4, 5), Circle(3), Rectangle(2, 8)]
for shape in shapes:
    print(f"{shape.__class__.__name__}: area = {shape.area():.2f}")

This is the power of polymorphism the loop doesn't need to know the type of each shape.

isinstance() and method resolution

class Vehicle:
    def move(self): return "moving"

class Car(Vehicle):
    def move(self): return "driving"

class ElectricCar(Car):
    def move(self): return "driving silently"

tesla = ElectricCar()
print(isinstance(tesla, ElectricCar))  # True
print(isinstance(tesla, Car))          # True
print(isinstance(tesla, Vehicle))      # True
print(tesla.move())                    # driving silently
print(ElectricCar.__mro__)             # shows resolution order

Common Mistakes

  • Forgetting to call super().__init__() in the child parent attributes won't be set up
  • Overriding a method but accidentally changing its signature breaks code that expects the parent interface
  • Diamond inheritance without understanding MRO use ClassName.__mro__ to debug resolution order

Note

Prefer composition over inheritance when the relationship is "has-a" rather than "is-a". A Car "has-a" Engine (composition) is cleaner than a Car "is-a" Engine (inheritance). Reserve inheritance for genuine "is-a" relationships.

Exercises

Write Python code to solve each exercise. Run it in your browser and check your output.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What does `super().__init__(...)` do in a child class?