AiTechWorlds
AiTechWorlds
Every company has a hierarchy. At the top sits the CEO responsible for strategy, stakeholder relations, and overall company direction. Below the CEO is the CTO, who inherits all those general leadership responsibilities and adds specific technical ones: overseeing the engineering teams, choosing the tech stack, driving architectural decisions.
Further down is the Software Engineer, who inherits from the technical leadership role: they still attend meetings, still communicate with stakeholders at some level but their day to day is writing and reviewing code.
Each level in the chart inherits from the one above it. Nobody re defines what "showing up to work" means at every level they inherit it and, where needed, extend or override it.
That is exactly how inheritance works in OOP.
Imagine building a fleet of vehicles without inheritance:
class Car:
def start(self): print("Car starts")
def stop(self): print("Car stops")
def honk(self): print("Beep!")
class Truck:
def start(self): print("Truck starts") # Copy-paste
def stop(self): print("Truck stops") # Copy-paste
def honk(self): print("HOOOONK!")Every shared behaviour is duplicated. Fix a bug in start() and you must fix it in every class. Inheritance solves this by putting shared behaviour in one place.
class Parent:
pass
class Child(Parent): # Child inherits from Parent
passThe child class gains everything the parent defined all attributes, all methods automatically.
# Level 1 — the base class
class Vehicle:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def start(self):
print(f"{self.make} {self.model} engine starting...")
def stop(self):
print(f"{self.make} {self.model} stopping.")
def __str__(self):
return f"{self.year} {self.make} {self.model}"# Level 2 — Car inherits from Vehicle
class Car(Vehicle):
def __init__(self, make, model, year, num_doors):
super().__init__(make, model, year) # Call parent's __init__
self.num_doors = num_doors # Add Car-specific data
def honk(self):
print("Beep beep!")
def __str__(self):
# Extend parent's __str__ rather than replace it entirely
base = super().__str__()
return f"{base} ({self.num_doors}-door)"# Level 3 — ElectricCar inherits from Car
class ElectricCar(Car):
def __init__(self, make, model, year, num_doors, battery_kwh):
super().__init__(make, model, year, num_doors) # Call Car's __init__
self.battery_kwh = battery_kwh # Add EV-specific data
def start(self):
# OVERRIDE Vehicle's start — EV doesn't have an engine noise
print(f"{self.make} {self.model} silently powering up...")
def charge(self):
print(f"Charging {self.battery_kwh} kWh battery.")
def __str__(self):
base = super().__str__()
return f"{base} [EV, {self.battery_kwh} kWh]"# Create objects at each level
van = Vehicle("Ford", "Transit", 2020)
sedan = Car("Honda", "Accord", 2022, 4)
ev = ElectricCar("Tesla", "Model S", 2024, 4, 100)
# Vehicle behaviour
van.start()
van.stop()
print(van)
print("---")
# Car inherits start/stop, adds honk
sedan.start()
sedan.honk()
print(sedan)
print("---")
# ElectricCar OVERRIDES start, inherits stop and honk
ev.start()
ev.stop()
ev.honk()
ev.charge()
print(ev)Output:
Ford Transit engine starting...
Ford Transit stopping.
2020 Ford Transit
---
Honda Accord engine starting...
Beep beep!
2022 Honda Accord (4-door)
---
Tesla Model S silently powering up...
Tesla Model S stopping.
Beep beep!
Charging 100 kWh battery.
2024 Tesla Model S (4-door) [EV, 100 kWh]When ElectricCar extends Car which extends Vehicle:
ElectricCar can call stop() defined on Vehicle, inherited through Car.ElectricCar can call honk() defined on Car, inherited directly.ElectricCar overrides start() it defines its own version, which shadows the one on Vehicle.You can verify the full chain with isinstance():
print(isinstance(ev, ElectricCar)) # True
print(isinstance(ev, Car)) # True
print(isinstance(ev, Vehicle)) # Truesuper() Functionsuper() is how you call the parent class's version of a method. It is most critical in __init__:
class Car(Vehicle):
def __init__(self, make, model, year, num_doors):
super().__init__(make, model, year) # Run Vehicle's __init__ first
self.num_doors = num_doors # Then add Car's own setupWithout super().__init__(...):
self.make, self.model, and self.year would never be set.Always call
super().__init__()in a child class unless you have a specific reason not to.
Overriding is simply defining a method in the child with the same name as one in the parent. The child's version takes precedence for that class.
You have three choices when overriding:
super().super().method() first (or last), then add new behaviour.super().method() only under certain conditions.class ElectricCar(Car):
def start(self):
# Full replacement — EV behaviour is completely different
print(f"{self.make} {self.model} silently powering up...")Inheritance creates tight coupling if the parent class changes, every child class may break. Prefer inheritance only when the relationship is genuinely "is a":
| Situation | Right choice |
|---|---|
ElectricCar is a Car | Inheritance correct |
Car has an Engine | Composition use an attribute, not inheritance |
Logger wants to add logging to Service | Mixin or composition |
| You want to share one method across unrelated classes | Module level function or mixin |
"Favour composition over inheritance" is one of the classic principles of OOP design. Inheritance is powerful but composition (giving an object a reference to another object) is often more flexible and less fragile.
class Child(Parent): syntax to declare inheritance.super().__init__(...) in the child's __init__ to properly initialise the parent portion.super().method() to extend rather than fully replace.University learning companion
Object-Oriented Programming (OOP) · Single Inheritance: Parent and Child Classes
Complete the steps without looking at the answer first; record evidence rather than only a final result.
These are primary or established learning references for this subject. Check the relevant chapter or specification for the exact topic and version.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises