0–5 min
Real Hook
5–25 min
Core Concept
25–45 min
Live Coding
45–55 min
You Code It
55–60 min
Cheat Sheet
🔥 Real-World Hook (0–5 min)
Why does updating Instagram not require reinstalling your phone's OS? Why does a junior developer at Swiggy only need to change one Restaurant class to update how all restaurants behave across the app?
Object-Oriented Programming. Everything is a blueprint (class). One change in the blueprint updates every object built from it. This is how Python backends at Swiggy, Razorpay, and Urban Company are structured.
🌍 The 4 Pillars — Python Style (5–25 min)
💡 Analogies
Encapsulation — A capsule hides the medicine. You swallow it, not mix chemicals. Private attributes + public methods.
Inheritance — A SavingsAccount IS a BankAccount. Gets everything from parent, adds its own rules.
Polymorphism — area() on a Circle vs Rectangle — same name, different result.
Abstraction — You drive a car without knowing the engine. Abstract base class hides complexity.
💻 Live Coding — Bank Account Hierarchy (25–45 min)
class BankAccount:
# __init__ is Python's constructor
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance # _ prefix = "treat as private"
self._transactions = []
def deposit(self, amount):
if amount > 0:
self._balance += amount
self._transactions.append(amount)
def withdraw(self, amount):
if amount > self._balance:
print("Insufficient funds!")
else:
self._balance -= amount
def get_balance(self):
return self._balance
def __str__(self): # what print() shows — dunder method
return f"{self.owner}: ₹{self._balance}"
class SavingsAccount(BankAccount): # inherits BankAccount
MIN_BALANCE = 500
def withdraw(self, amount): # Polymorphism: override parent method
if self._balance - amount < self.MIN_BALANCE:
print("Cannot withdraw — min balance ₹500 required")
else:
super().withdraw(amount) # call parent's method
class LoanAccount(BankAccount):
def __init__(self, owner, balance, rate):
super().__init__(owner, balance)
self.rate = rate
def calculate_interest(self, months):
return self._balance * self.rate * months / 1200
# Demo
acc = BankAccount("Priya", 10000)
sav = SavingsAccount("Ravi", 10000)
loan = LoanAccount("Anita", 50000, 12) # 12% p.a.
sav.withdraw(9600) # "Cannot withdraw — min balance ₹500 required"
sav.withdraw(5000) # OK
print(sav) # "Ravi: ₹5000"
print(loan.calculate_interest(6))# ₹3000
🎯 You Code It (45–55 min)
- Create an
Employee class: name, salary; method work() prints "{name} is working"
- Create
Manager(Employee) — add team_size, override work() to print "{name} is managing {team_size} people"
- Create
Contractor(Employee) — add hours_worked, add method calculate_pay() returning hours × ₹500
- Add
__str__ to Employee that shows name + salary
- Create one of each, call
work() on each — see polymorphism: same method, different output
- Show: Print all three objects + all three
work() outputs
📄 Day 4 Cheat Sheet — OOP in Python
Class Basics
| class Car: | Define class |
| def __init__(self, x): | Constructor |
| self.speed = x | Instance attribute |
| car = Car(100) | Create object |
| car.speed | Access attribute |
| _name | Convention: private |
Inheritance
| class Dog(Animal): | Inherit |
| super().__init__(x) | Call parent constructor |
| super().method() | Call parent method |
| override method | Just redefine it |
| isinstance(obj, Cls) | Check type |
Dunder Methods
| __init__ | Constructor |
| __str__ | What print() shows |
| __repr__ | Developer string |
| __len__ | len(obj) |
| __eq__ | obj1 == obj2 |
| __lt__ | obj1 < obj2 |
Class vs Instance
| class X: count = 0 | Class attribute (shared) |
| self.name = x | Instance attribute (unique) |
| @classmethod | Method on the class itself |
| @staticmethod | Utility, no self/cls |
| @property | Getter with dot syntax |