Inheritance and Polymorphism — Building Hierarchical and Flexible Systems
Inheritance and polymorphism are two of the most powerful principles in Object-Oriented Programming (OOP).
Chapter 5: Object-Oriented Programming (OOP)
Sub-chapter: Inheritance and Polymorphism — Building Hierarchical and Flexible Systems
Inheritance and polymorphism are two of the most powerful principles in Object-Oriented Programming (OOP).
They allow you to reuse, extend, and customize code while maintaining a clear and scalable design.
🧱 What Is Inheritance?
Inheritance allows one class (the child or subclass) to derive from another class (the parent or superclass).
This enables the child class to inherit all attributes and methods of the parent, and optionally override or extend them.
Example: Basic Inheritance
class Animal:
def speak(self):
return "Some sound"
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
dog = Dog()
cat = Cat()
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
🧩 Why Use Inheritance?
✅ Avoids code duplication.
✅ Encourages code reuse and organization.
✅ Allows hierarchical design and extension.
✅ Enables polymorphism — treating different objects uniformly.
🧠 Types of Inheritance
| Type | Description | Example |
|---|---|---|
| Single | A subclass inherits from one superclass. | Dog → Animal |
| Multilevel | A subclass acts as a parent for another subclass. | A → B → C |
| Multiple | A class inherits from multiple parent classes. | C(A, B) |
| Hierarchical | Multiple subclasses inherit from the same parent. | Dog, Cat → Animal |
| Hybrid | A combination of multiple inheritance patterns. | Complex real-world systems |
🧮 Method Overriding and super()
When a subclass redefines a method from its parent, the new version overrides the original.
super() is used to call the parent’s version of a method.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)
super()ensures proper method chaining, especially in multi-level or multiple inheritance.
🔄 Polymorphism: One Interface, Multiple Implementations
Polymorphism allows different objects to respond to the same method call in different ways.
def make_sound(animal):
print(animal.speak())
animals = [Dog(), Cat()]
for a in animals:
make_sound(a)
Output:
Woof!
Meow!
Each subclass provides its own
speak()implementation — same interface, different behavior.
🧩 Abstract Base Classes (ABC)
To enforce a structure across subclasses, Python provides the abc module.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
You cannot instantiate
Shapedirectly — it defines an interface that all subclasses must implement.
🧱 Real-World Example — Employee Management System
This example demonstrates inheritance, polymorphism, and abstraction in a realistic scenario.
from abc import ABC, abstractmethod
class Employee(ABC):
def __init__(self, name, base_salary):
self.name = name
self.base_salary = base_salary
@abstractmethod
def calculate_bonus(self):
pass
def get_info(self):
return f"{self.name}: ${self.base_salary}"
class Developer(Employee):
def __init__(self, name, base_salary, programming_language):
super().__init__(name, base_salary)
self.programming_language = programming_language
def calculate_bonus(self):
return self.base_salary * 0.10
class Manager(Employee):
def __init__(self, name, base_salary, team_size):
super().__init__(name, base_salary)
self.team_size = team_size
def calculate_bonus(self):
return self.base_salary * (0.05 * self.team_size)
employees = [
Developer("Alice", 80000, "Python"),
Manager("Bob", 100000, 3),
]
for emp in employees:
print(f"{emp.get_info()} | Bonus: ${emp.calculate_bonus():.2f}")
Output:
Alice: $80000 | Bonus: $8000.00
Bob: $100000 | Bonus: $15000.00
📊 UML-Style Class Diagram
+-----------------+
| Employee (ABC) |
+-----------------+
| - name |
| - base_salary |
+-----------------+
| + calculate_bonus() (abstract) |
| + get_info() |
+-----------------+
^
|
--------------------
| |
+-----------+ +-----------+
| Developer | | Manager |
+-----------+ +-----------+
| - language | | - team_size |
| + calculate_bonus() | + calculate_bonus() |
+-----------+ +-----------+
🧭 Both
DeveloperandManagershare the same interface fromEmployee, but implement behavior differently.
🧬 Multiple Inheritance and Method Resolution Order (MRO)
Python supports multiple inheritance — a class can inherit from multiple parent classes.
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
def show(self):
print("C")
class D(B, C):
pass
d = D()
d.show()
print(D.mro())
Output:
B
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
Python uses the C3 linearization algorithm to determine the MRO — the order in which classes are searched for methods.
⚖️ Composition vs Inheritance
| Concept | Definition | When to Use |
|---|---|---|
| Inheritance | “Is a” relationship — reuse structure from a base class. | Shared behavior, polymorphism. |
| Composition | “Has a” relationship — reuse functionality by including other objects. | Modular design, flexible architecture. |
Example:
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self.engine = Engine() # Composition
def drive(self):
self.engine.start()
print("Car is moving!")
🧩 Best Practices
✅ Favor composition over deep inheritance trees.
✅ Keep class hierarchies shallow and meaningful.
✅ Use super() for clean method chaining.
✅ Abstract shared behavior into base classes.
✅ Avoid inheriting from multiple classes unnecessarily — use mixins if needed.
✅ Document overridden methods clearly.
🧾 Summary
- Inheritance enables code reuse through hierarchical class design.
- Polymorphism allows consistent behavior across different object types.
- Abstract classes enforce structure and consistency.
- Multiple inheritance requires understanding MRO to avoid ambiguity.
- Prefer composition for flexibility, inheritance for shared logic.
By mastering inheritance and polymorphism, you can design systems that are modular, extensible, and maintainable — key qualities in advanced software engineering.