Inheritance
Create extensible class hierarchies, reuse behavior safely, and design APIs that stay flexible as your codebase grows.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- • How subclasses inherit methods and attributes from parent classes
- • Overriding methods and calling super()
- • Method Resolution Order (MRO) in Python
- • Abstract base classes with abc.ABC
- • Polymorphism: writing code that works on multiple types
1️⃣ Why Inheritance? Why Polymorphism?
🏠 Real-World Analogy:
Think of a family tree . Children inherit traits from their parents (eye color, height) but can also have their own unique traits. In programming, a child class inherits features from a parent class but can add or change behaviors.
Concept
What It Means
Example
Inheritance
A child class reuses and extends a parent class
Dog inherits from Animal
Polymorphism
"Many forms" - same method name, different behaviors
.speak() returns "Woof!" or "Meow!"
Polymorphism means "many forms": different classes expose the same method name but implement it differently, so your high-level code doesn't care which concrete type it's using—only that it supports the interface.
💡 Why This Matters: This improves extensibility , testability , and readability in real projects like games, APIs, and data pipelines.
2️⃣ Core Inheritance Syntax
📝 The Basic Pattern:
✨ Key Point: The child inherits ALL attributes and methods from the parent. You can then override (replace) or extend (add to) them.
3️⃣ super() and Constructor Chaining
🤔 What is super()?
super() is a special function that gives you access to the parent class . It's like saying "Hey, parent class, please run YOUR version of this method first!"
Without super()
With super()
Parent's __init__ is NOT called
Parent's __init__ IS called ✅
Parent's attributes are missing
All parent attributes are set up properly ✅
4️⃣ Method Overriding & Extension Patterns
Override to change behavior; extend to add extra steps:
5️⃣ Multiple Inheritance & MRO (Method Resolution Order)
A smartphone inherits features from both a phone AND a camera . That's multiple inheritance—one class getting abilities from multiple parents!
Term
Multiple Inheritance
A class inherits from 2+ parent classes
MRO
Method Resolution Order—the order Python checks classes for a method
6️⃣ When to Use Inheritance (and When Not)
✅ Use when:
- • Clear IS-A relationship: Dog is a Animal, Car is a Vehicle.
- • You truly want to reuse base logic and maybe override small parts.
❌ Avoid when:
- • Relationship is HAS-A (composition is better): A Car has an Engine.
- • You're forcing a deep chain just to share helpers (prefer composition or mixins).
Rule of thumb: Favor composition over inheritance unless the IS-A relation is obvious and stable.
7️⃣ Polymorphism via Duck Typing
🦆 What is Duck Typing?
"If it walks like a duck and quacks like a duck, it's a duck!"
In Python, we don't care what type an object is—we only care what it can do . If it has a .speak() method, we can call it!
Traditional OOP
Python Duck Typing
Must inherit from same parent
No inheritance required! ✅
Strict type checking
Just needs the right methods ✅
✨ Key Insight: This is duck typing in action! Python is flexible—it doesn't need formal interfaces or shared parents.
8️⃣ Abstract Base Classes (ABCs) for Robust APIs
🤔 What is an Abstract Class?
An abstract class is like a template or contract . It says "any class that inherits from me MUST implement these methods" but doesn't provide the implementation itself.
Regular Class
Abstract Class
Can be instantiated directly
Cannot be instantiated ❌
All methods have implementations
Some methods are just "promises"
Child classes can override optionally
Child classes MUST implement abstract methods
9️⃣ Protocols (typing) for Structural Polymorphism
With type hints you can express "any object with .area() is acceptable"—even if it doesn't inherit from Shape.
This is powerful for plug-in systems and testing.
🔟 Liskov Substitution Principle (LSP)
🏠 Simple Explanation:
If you have code that works with Animal , it should also work with Dog or Cat without any surprises. A child class should behave like its parent, not break expectations.
✅ Good (Follows LSP)
❌ Bad (Violates LSP)
Bird.fly() → flies as expected
Penguin.fly() → raises error!
Rectangle.area() → returns area
Square.area() → changes width when you set height?!
⚠️ Signs You're Violating LSP:
- • Child requires stricter inputs than parent
- • Child returns different types than parent promised
- • Child throws errors the parent never would
💡 Rule of Thumb: If you need to check "is this a Dog or a Cat?" before calling a method, you might be violating LSP. Good polymorphism means you don't need to check!
1️⃣1️⃣ Composition vs Inheritance — Concrete Example
Composition is easier to refactor and avoids MRO tangles.
1️⃣2️⃣ Mixins: Small, Focused Behavior Blocks
A mixin is a parent with only helper behavior, no standalone identity.
Use mixins sparingly, name them *Mixin , and avoid shared state.
1️⃣3️⃣ Real-World Hierarchy: Shapes & Polymorphic Area
1️⃣4️⃣ Overriding Pitfalls & Best Practices
- ✅ Always call super() in __init__ if parent defines it (helps multiple inheritance).
- ✅ Keep overrides behaviorally compatible with the base.
- ✅ Document side effects and invariants (e.g., "area() returns non-negative float").
- ✅ Unit-test with base type references to catch LSP issues.
1️⃣5️⃣ Polymorphism Beyond Methods: Operators & Special Methods
Special methods let your classes participate in Python's operators—another form of polymorphism.
1️⃣6️⃣ Testing Polymorphism (Strategy Pattern Feel)
No inheritance required, but you still get clean polymorphism. If you later need guarantees, move to an ABC/Protocol.
1️⃣7️⃣ Multiple Inheritance Done Right (Cooperative super())
All classes call super() with **kw , so init flows through the MRO smoothly.
1️⃣8️⃣ Performance & Practicality
- ⚡ Virtual dispatch (method lookup) is fast enough for most apps.
- 📐 Prefer small, stable bases with clear contracts over deep trees.
- 🧹 Keep methods short; big conditionals might indicate a missing subtype.
🎯 1️⃣9️⃣ Practice Challenge (with Guided Solution)
Task:
- Create an abstract Shape with area() .
- Implement Rectangle(w,h) and Circle(r) .
- Build a list of shapes, then compute total area with polymorphism.
📋 Quick Reference — Inheritance
class Dog(Animal):
Inherit from Animal
super().__init__(name)
Call parent constructor
def speak(self):
Override a parent method
Dog.mro()
See Method Resolution Order
from abc import ABC, abstractmethod
Abstract base class
You now understand inheritance, method overriding, super(), MRO, and polymorphism — the tools that make Python class hierarchies clean and extensible.
Up next: Decorators & Advanced Features — learn to wrap functions with reusable behaviour using Python's elegant decorator syntax.
Practice quiz
How do you make class Dog inherit from class Animal?
- class Dog -> Animal:
- class Dog inherits Animal:
- class Dog(Animal):
- class Dog extends Animal:
Answer: class Dog(Animal):. Python uses parentheses: class Dog(Animal): puts the parent class inside the parentheses.
Inside a child's __init__, how do you call the parent class's __init__?
- super().__init__(name)
- parent.__init__(name)
- Animal.init(name)
- self.super(name)
Answer: super().__init__(name). super().__init__(name) runs the parent constructor so its setup (like self.name) actually happens.
What does Duck.mro() return for class Duck(Walker, Swimmer)?
- Walker
- Swimmer
- Duck
The MRO lists Duck first, then parents left-to-right (Walker, Swimmer), then object.
What does the @abstractmethod decorator (from abc) enforce?
- The method runs automatically
- Child classes must implement that method
- The method becomes static
- The method is cached
Answer: Child classes must implement that method. An abstractmethod is a promise: any concrete subclass must implement it, or instantiation fails.
What is 'duck typing' in Python?
- Caring only about whether an object has the needed method, not its type
- Requiring all objects to share a parent class
- A way to copy ducks
- Strict compile-time type checking
Answer: Caring only about whether an object has the needed method, not its type. Duck typing: if it has .speak(), you can call it — Python checks behavior, not the exact type.
Given Vector2 with __add__ defined, what does Vector2(1, 2) + Vector2(3, 4) produce?
- Vector2(3, 8)
- Vector2(1, 2, 3, 4)
- Vector2(4, 6)
- a TypeError
Answer: Vector2(4, 6). __add__ adds component-wise: x=1+3=4, y=2+4=6, giving Vector2(4, 6).
An abstract base class created with abc.ABC and an abstractmethod...
- can be instantiated directly
- cannot be instantiated directly
- has no methods
- must inherit from object explicitly
Answer: cannot be instantiated directly. Abstract classes act as templates/contracts and cannot be instantiated directly.
Which relationship signals you should prefer composition over inheritance?
- IS-A (Dog is an Animal)
- Any 2-level hierarchy
- Polymorphic methods
- HAS-A (Car has an Engine)
Answer: HAS-A (Car has an Engine). A HAS-A relationship (a Car has an Engine) is best modeled with composition, not inheritance.
The Liskov Substitution Principle (LSP) says a subclass should...
- always add new attributes
- be usable anywhere its parent is expected, without surprises
- never override methods
- require stricter inputs than the parent
Answer: be usable anywhere its parent is expected, without surprises. LSP: code that works with the parent type should work with any subclass without breaking expectations.
What is a mixin?
- A class that cannot be subclassed
- A function decorator
- A small parent that adds focused behavior, with no standalone identity
- A way to merge two instances
Answer: A small parent that adds focused behavior, with no standalone identity. A mixin is a small, behavior-only parent (named *Mixin) you mix in to add reusable functionality.
Continue this course
- Previous: Object-Oriented Programming
- Next: Decorators & Advanced Features