Phase 6 🏛️ — OOP
Topics: Classes, objects, __init__, inheritance, methods, encapsulation
Object-Oriented Programming lets you model real-world entities as code. Classes are the blueprint; objects are the things you build from them.
🔄 Exercise Flow
📚 Prerequisites
Before starting these exercises, make sure you've read:
- Classes & Objects — Defining classes and creating instances
- Constructors — The
__init__method - Inheritance — Extending classes
- Abstraction & Encapsulation — Hiding implementation details
- Access Modifiers — Public, protected, and private attributes
🔰 Starter: Bank Account Class
Time: 12 minutes
Design a BankAccount class with deposit, withdrawal, and balance display functionality.
Learning Objectives
- Define a class with
__init__constructor - Create instance attributes (
self.attr) - Define instance methods that modify state
- Use encapsulation with private attributes (
__attr)
Starter Code
# Starter: Bank Account Class
class BankAccount:
def __init__(self, owner, initial_balance=0):
# TODO: Set owner (public) and __balance (private)
pass
def deposit(self, amount):
# TODO: Add amount to balance if amount > 0
pass
def withdraw(self, amount):
# TODO: Subtract amount if balance is sufficient
pass
def get_balance(self):
# TODO: Return the current balance
pass
def __str__(self):
# TODO: Return a string like "Account owner: Alice | Balance: $500.00"
pass
# --- Test your class ---
account = BankAccount("Alice", 1000)
account.deposit(500)
account.withdraw(200)
print(account) # Account owner: Alice | Balance: $1300.00
print(account.get_balance()) # 1300
# print(account.__balance) # This should raise an AttributeError!
Expected Output
Account owner: Alice | Balance: $1300.00
1300
⭐ Medium: Library System with Inheritance
Time: 22 minutes
Build a library system with a base LibraryItem class and subclasses Book, DVD, and Magazine that inherit and extend its functionality.
Learning Objectives
- Create a base class with shared attributes and methods
- Use inheritance (
class Child(Parent)) - Override methods in subclasses
- Use
super()to call parent methods - Implement polymorphic behaviour
Starter Code
# Medium: Library System with Inheritance
class LibraryItem:
def __init__(self, title, item_id, is_borrowed=False):
self.title = title
self.item_id = item_id
self._is_borrowed = is_borrowed
def borrow(self):
if not self._is_borrowed:
self._is_borrowed = True
return f"'{self.title}' borrowed successfully."
return f"'{self.title}' is already borrowed."
def return_item(self):
if self._is_borrowed:
self._is_borrowed = False
return f"'{self.title}' returned successfully."
return f"'{self.title}' was not borrowed."
def __str__(self):
status = "Available" if not self._is_borrowed else "Borrowed"
return f"[{self.item_id}] {self.title} — {status}"
# TODO 1: Create Book(LibraryItem) with author and page_count
# TODO 2: Create DVD(LibraryItem) with director and duration
# TODO 3: Create Magazine(LibraryItem) with issue_number
# TODO 4: Each subclass should override __str__ to include its extra info
# TODO 5: Book.borrow() should check if it's a reference copy (can't be borrowed)
# TODO 6: Create a Library class that manages a collection of LibraryItems
# Your code here 👇
Expected Output
=== LIBRARY CATALOG ===
[B001] Python Crash Course — Eric Matthes (350 pages) — Available
[B002] Reference: Python Guide (Reference Copy — Cannot be borrowed)
[D001] Inception — Christopher Nolan (148 min) — Available
[M001] Tech Monthly — Issue #42 — Borrowed
Operations:
✓ 'Python Crash Course' borrowed successfully.
✗ 'Reference: Python Guide' is a reference copy and cannot be borrowed.
✓ 'Python Crash Course' returned successfully.
🏆 Hard: E-Commerce System with Full OOP Design
Time: 40 minutes
Design a complete e-commerce system using OOP principles: inheritance, encapsulation, polymorphism, composition, and abstract base classes.
Learning Objectives
- Use abstract base classes (
ABC) and abstract methods - Implement multiple levels of inheritance
- Use composition (a class containing instances of other classes)
- Apply proper encapsulation with property decorators
- Build a realistic, extensible system design
Starter Code
# Hard: E-Commerce System with Full OOP Design
from abc import ABC, abstractmethod
# --- Abstract Base Class ---
class Product(ABC):
def __init__(self, product_id, name, price, stock):
self._product_id = product_id
self._name = name
self._price = price
self._stock = stock
@property
def name(self):
return self._name
@property
def price(self):
return self._price
@property
def stock(self):
return self._stock
@stock.setter
def stock(self, value):
if value >= 0:
self._stock = value
else:
raise ValueError("Stock cannot be negative")
@abstractmethod
def get_description(self):
pass
@abstractmethod
def get_category(self):
pass
# TODO 1: Implement Electronics(Product) with warranty_months and brand
# TODO 2: Implement BookProduct(Product) with author and pages
# TODO 3: Implement Clothing(Product) with size and material
# TODO 4: Create a Customer class with name, email, loyalty_points
# TODO 5: Create an Order class that contains:
# - A customer
# - A list of OrderItem (product + quantity)
# - Methods to add_item, remove_item, get_total, apply_discount
# - Property to check if order qualifies for free shipping
# TODO 6: Create an Inventory class that manages all Products
# TODO 7: Implement a ShoppingCart (composition: cart contains products)
# Your code here 👇
Expected Output
═══════════════════════════════════════
PYTHONMART — OOP E-Commerce
═══════════════════════════════════════
Product Catalog:
[ELEC] Sony Wireless Headphones — $149.99 (2yr warranty) ⭐
[BOOK] Fluent Python — $49.99 by Luciano Ramalho (792 pages) 📖
[CLOTH] Python Logo Hoodie — $39.99 (Size: L, Cotton) 👕
Customer: Alice Johnson (Gold Member — 250 points)
🛒 Shopping Cart:
1. Sony Wireless Headphones x1 = $149.99
2. Fluent Python x2 = $99.98
3. Python Logo Hoodie x1 = $39.99
─────────────────────────────────
Subtotal: $289.96
Discount: -$28.99 (10% Gold Member)
Shipping: $0.00 (Free! Over $200)
─────────────────────────────────
Total: $260.97
📦 Order #ORD-2025-001 placed successfully!
💡 Tips for Success
selfis always the first parameter — every instance method takesselfas its first argument, referring to the current object.- Use
@propertyfor getters and setters — it's the Pythonic way to encapsulate attributes without writingget_balance()/set_balance()methods. - Favour composition over inheritance — "has-a" is often more flexible than "is-a". A
Carhas anEngine, rather than aCarbeing a subclass ofEngine. - Abstract base classes define the interface — they force subclasses to implement specific methods, ensuring consistency.