Python Inheritance
Understand how to create parent and child classes, use super(), override methods, and apply polymorphism in Python.
What is Inheritance?
Inheritance allows a new class (the child or subclass) to inherit attributes and methods from an existing class (the parent or superclass). This promotes code reuse and creates a logical hierarchy.
The child class can use everything from the parent, add its own unique features, or override parent methods to provide specialised behaviour.
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def speak(self):
return f"{self.name} makes a sound"
class Dog(Animal): # Dog inherits from Animal
def __init__(self, name, breed):
super().__init__(name, "Canine") # call parent __init__
self.breed = breed
def speak(self): # override parent method
return f"{self.name} barks!"
buddy = Dog("Buddy", "Labrador")
print(buddy.species) # Canine (inherited attribute)
print(buddy.speak()) # Buddy barks! (overridden method)
The super() function calls the parent class's method, letting you extend rather than replace behaviour.
Method Overriding and super()
When a child class defines a method with the same name as one in the parent, it overrides the parent's version. You can still access the parent's implementation using super().
class Vehicle:
def __init__(self, make, year):
self.make = make
self.year = year
def describe(self):
return f"{self.year} {self.make}"
class ElectricCar(Vehicle):
def __init__(self, make, year, battery_kwh):
super().__init__(make, year) # reuse parent init
self.battery_kwh = battery_kwh
def describe(self): # override with extra info
base = super().describe() # get parent's description
return f"{base} (Electric, {self.battery_kwh} kWh)"
tesla = ElectricCar("Tesla Model 3", 2025, 75)
print(tesla.describe())
# 2025 Tesla Model 3 (Electric, 75 kWh)
Polymorphism
Polymorphism means "many forms." It allows different classes to be treated through the same interface. When multiple classes implement the same method name, you can call that method on any of them without knowing the specific class.
class Shape:
def area(self):
raise NotImplementedError("Subclasses must implement area()")
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
import math
return math.pi * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
# Polymorphism in action
shapes = [Circle(5), Rectangle(4, 6), Circle(3)]
for shape in shapes:
print(f"{type(shape).__name__}: area = {shape.area():.2f}")
# Circle: area = 78.54
# Rectangle: area = 24.00
# Circle: area = 28.27
Each shape calculates its area differently, but we call .area() on all of them uniformly. This is polymorphism.
Key Vocabulary
Inheritance
A mechanism where a child class receives attributes and methods from a parent class.
super()
A built-in function that returns a proxy object allowing you to call methods from the parent class.
Method Overriding
When a child class redefines a method inherited from its parent class with its own implementation.
Polymorphism
The ability of different classes to respond to the same method call in their own way.
Worked Examples
Create an Employee hierarchy with a Manager subclass
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def get_pay(self):
return self.salary
def __str__(self):
return f"{self.name} (${self.salary:,.0f}/yr)"
class Manager(Employee):
def __init__(self, name, salary, bonus):
super().__init__(name, salary)
self.bonus = bonus
def get_pay(self):
return self.salary + self.bonus
def __str__(self):
return f"{self.name} (${self.get_pay():,.0f}/yr incl. bonus)"
emp = Employee("Alice", 70000)
mgr = Manager("Bob", 90000, 15000)
print(emp) # Alice ($70,000/yr)
print(mgr) # Bob ($105,000/yr incl. bonus)
print(mgr.get_pay()) # 105000
Key point: Manager overrides both get_pay() and __str__() while reusing the parent's __init__ via super().
Use isinstance() and issubclass() to check relationships
class Animal:
pass
class Dog(Animal):
pass
class Cat(Animal):
pass
rex = Dog()
whiskers = Cat()
print(isinstance(rex, Dog)) # True
print(isinstance(rex, Animal)) # True (Dog IS an Animal)
print(isinstance(rex, Cat)) # False
print(issubclass(Dog, Animal)) # True
print(issubclass(Cat, Dog)) # False
isinstance() checks if an object is an instance of a class (or its parents). issubclass() checks the class hierarchy directly.
Multiple inheritance and method resolution order (MRO)
class Flyer:
def move(self):
return "Flying through the air"
class Swimmer:
def move(self):
return "Swimming through water"
class Duck(Flyer, Swimmer):
pass # inherits from both
donald = Duck()
print(donald.move()) # Flying through the air (Flyer comes first)
# Check the Method Resolution Order
print(Duck.__mro__)
# (Duck, Flyer, Swimmer, object)
MRO determines which parent method is called when there is a conflict. Python uses the C3 linearisation algorithm, checking left-to-right in the inheritance list.
Knowledge Check
Select the correct answer for each question. Click "Check Answer" to see if you are right.
Question 1
What does super().__init__() do inside a child class?
Question 2
What is method overriding?
Question 3
Given class Cat(Animal), what does isinstance(my_cat, Animal) return?
Question 4
What is polymorphism in OOP?
Question 5
In class Duck(Flyer, Swimmer), which class's move() method is called first?
Key Concepts Summary
- ●Inheritance lets a child class reuse and extend a parent class's code.
- ●super() calls the parent's methods, essential for proper initialisation chains.
- ●Method overriding gives the child class its own version of a parent method.
- ●Polymorphism allows the same method name to behave differently across related classes.
- ●MRO (Method Resolution Order) determines which parent's method is called in multiple inheritance.