Inheritance & Polymorphism
Overview
Inheritance lets new classes reuse code from existing classes, and polymorphism lets different classes share interfaces.
Learning Objectives
- Create child classes that inherit from parent classes.
- Override parent methods and use super() to run constructor logic.
- Understand multiple inheritance hierarchies.
Concept Explanation
Inheritance defines parent-child relationships. A subclass inherits attributes and methods from its parent. Use super() to call methods and constructors from the parent class. Polymorphism lets subclasses override methods to implement custom behavior while keeping the same interface.
Code Examples
Example 1 — Basics
This example introduces the fundamental syntax and concepts.
class Vehicle:
def start(self): return 'Engine started'
class Car(Vehicle):
pass
Example 2 — Everyday Usage
This example demonstrates a realistic scenario handling business parameters.
class User:
def __init__(self, username):
self.username = username
def get_role(self): return 'Guest'
class Admin(User):
def __init__(self, username, level):
super().__init__(username) # Call parent constructor
self.level = level
def get_role(self): return 'Admin'
adm = Admin('alex', 3)
print(adm.username, adm.get_role())
Example 3 — Advanced Example
This example shows clean, production-grade code structure following senior development standards.
class MessageSender:
def send(self, recipient, body):
raise NotImplementedError('Subclasses must implement send')
class EmailSender(MessageSender):
def send(self, recipient, body):
print(f'Email sent to {recipient}: {body}')
class SMSSender(MessageSender):
def send(self, recipient, body):
print(f'SMS sent to {recipient}: {body}')
# Polymorphic function calling identical send interface
def alert_user(senders, user, text):
for s in senders:
s.send(user, text)
alert_user([EmailSender(), SMSSender()], 'alex@corp.com', 'System down')
Visual Flow
The following execution flow represents the step-by-step evaluation inside the interpreter:
Call method → Check subclass → Found? Run method : Check parent classes → Run parent method
Common Mistakes
Review these common pitfalls when working with this topic:
- Forgetting to call super().init() in subclass constructors, which leaves parent attributes uninitialized.
- Creating deeply nested inheritance hierarchies that are hard to understand.
- Modifying overridden method signatures, which breaks polymorphic interfaces.
- Using multiple inheritance without understanding how Python searches parents (MRO).
Best Practices
Enforce these Pythonic best practices in your codebase:
class Child(Parent):
def __init__(self, val):
self.val = val # Parent attributes remain uninitialized
class Child(Parent):
def __init__(self, val):
super().__init__()
self.val = val # Initializes parent attributes correctly
Quick Revision
Use these key summaries for last-minute revision:
- Inheritance reuse code from parent classes.
- super() invokes parent constructors and methods.
- Subclasses can override parent methods.
- Polymorphism allows different classes to share interfaces.
- Inheritance search order is determined by MRO.
- Prefer simple structure compositions.