Excellent.
DAY 20 is about real design decisions — the difference between code that works and code that scales, stays readable, and survives refactoring.
Most interviewers are not testing syntax here — they are testing engineering judgment.
🧠 DAY 20 — Inheritance, Composition & Mixins
(Pythonic Class Design & Tradeoffs)
🔑 CORE IDEA OF DAY 20
Inheritance is about “is-a”.
Composition is about “has-a”.
Python strongly prefers composition unless inheritance is unavoidable.
1️⃣ Inheritance — When It Makes Sense
Inheritance is appropriate when:
- There is a true subtype relationship
- Behavior is shared conceptually
- Subclasses can safely replace base class (LSP)
class Animal:
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return "woof"
This is good inheritance.
2️⃣ When Inheritance Becomes a Problem 🔥
class Car:
def start(self): ...
class ElectricCar(Car):
def refuel(self): ... # ❌ conceptual mismatch
Smell:
- Base class forces irrelevant behavior
- Subclass violates expectations
This leads to:
- Complex overrides
- Fragile hierarchies
- MRO confusion
3️⃣ Composition — Pythonic Default
class Engine:
def start(self):
print("engine start")
class Car:
def __init__(self):
self.engine = Engine()
def start(self):
self.engine.start()
Why this is better:
- Loosely coupled
- Easier testing
- Easier refactoring
- No inheritance entanglement
🧠 Prefer composition unless inheritance is truly required.
4️⃣ Mixins — Controlled Multiple Inheritance
A mixin:
- Provides a small, focused capability
- Is not a standalone class
- Is meant to be combined
class JSONSerializableMixin:
def to_json(self):
import json
return json.dumps(self.__dict__)
Usage:
class User(JSONSerializableMixin):
def __init__(self, name):
self.name = name
Mixins:
- Have no state (ideally)
- Do one thing well
- Rely on MRO cooperation
5️⃣ Rules for Safe Mixins (INTERVIEW EXPECTED)
✔ Mixin should:
- Be small
- Avoid
__init__ - Use
super()carefully - Assume nothing about base class except interface
❌ Mixin should NOT:
- Be instantiated alone
- Hold business state
- Depend on concrete class details
6️⃣ Cooperative Inheritance with super() (RECAP)
class A:
def f(self):
print("A")
class Mixin:
def f(self):
print("Mixin")
super().f()
class B(Mixin, A):
pass
B().f()
Output:
Mixin
A
Works because:
- All classes cooperate
- MRO respected
7️⃣ Composition vs Inheritance — Side-by-Side
| Scenario | Choose |
|---|---|
| Code reuse | Composition |
| Subtype relationship | Inheritance |
| Optional behavior | Mixin |
| Avoid coupling | Composition |
| Framework extension | Inheritance / mixins |
8️⃣ Multiple Inheritance (Use Carefully)
Python allows:
class C(A, B):
pass
But danger zones:
- Conflicting method names
- Confusing MRO
- Hard debugging
🧠 Use multiple inheritance only for mixins.
9️⃣ Real-World Python Examples
- Django CBVs → heavy mixin usage
- Flask → composition
- Pandas → composition + delegation
- Spark Python APIs → composition over inheritance
These libraries avoid deep hierarchies deliberately.
🔟 Composition Enables Dependency Injection
class Service:
def __init__(self, db):
self.db = db
Benefits:
- Easy mocking
- Easy testing
- Swappable implementations
This is professional-grade design.
🔥 INTERVIEW TRAPS (DAY 20)
Q1
Why is deep inheritance discouraged?
✔ Tight coupling
✔ Fragile base class
✔ MRO complexity
Q2
When is a mixin better than inheritance?
✔ Optional behavior
✔ Cross-cutting concerns
✔ No “is-a” relationship
Q3
Why mixins shouldn’t have __init__?
✔ Break MRO cooperation
✔ Cause double initialization
🧠 DAY 20 MENTAL CHECKLIST
Before choosing inheritance:
- Is this truly “is-a”?
- Will future subclasses break?
- Can composition solve this?
- Is behavior optional?
- Will MRO stay simple?
📝 DAY 20 ASSIGNMENT (MANDATORY)
1️⃣ Predict output (NO RUNNING):
class A:
def f(self):
print("A")
class M:
def f(self):
print("M")
super().f()
class B(M, A):
pass
B().f()
2️⃣ Explain clearly:
- Difference between inheritance and composition
- Why Python prefers composition
3️⃣ Design question:
How would you design logging behavior reusable across unrelated classes?
(Hint: mixin vs decorator)
🔜 DAY 21 PREVIEW
DAY 21 — Dunder Methods (Magic Methods & Operator Overloading)
You’ll learn:
- How operators actually work
__str__vs__repr__- Context managers
- How Python protocols enable elegance
When ready, say 👉 “START DAY 21”