OOP Capstone Projects
An object-oriented banking engine featuring encapsulation, deposit/withdrawal validation, transaction histories, and interest accrual:
# =========================================================================
# PROJECT 1: OBJECT-ORIENTED BANK MANAGEMENT SYSTEM
# =========================================================================
class BankAccount:
interest_rate = 0.04 # 4% Annual Interest (Class Variable)
def __init__(self, account_number, holder_name, initial_balance=0.0):
self.account_number = account_number
self.holder_name = holder_name
self._balance = float(initial_balance)
self.transaction_history = [f"Account opened with โน{initial_balance:,.2f}"]
@property
def balance(self):
return self._balance
def deposit(self, amount):
if amount <= 0:
return "โ Deposit amount must be positive!"
self._balance += amount
self.transaction_history.append(f"Deposited +โน{amount:,.2f}")
return f"โ
Deposited โน{amount:,.2f}. New Balance: โน{self._balance:,.2f}"
def withdraw(self, amount):
if amount > self._balance:
return f"โ Insufficient funds! Available Balance: โน{self._balance:,.2f}"
self._balance -= amount
self.transaction_history.append(f"Withdrew -โน{amount:,.2f}")
return f"โ
Withdrew โน{amount:,.2f}. Remaining Balance: โน{self._balance:,.2f}"
def apply_interest(self):
interest_earned = self._balance * BankAccount.interest_rate
self._balance += interest_earned
self.transaction_history.append(f"Interest credited +โน{interest_earned:,.2f}")
return f"๐ Interest of โน{interest_earned:,.2f} credited at {BankAccount.interest_rate*100}%"
def get_statement(self):
header = f"=== ๐ฆ STATEMENT: {self.holder_name} (Acc #{self.account_number}) ==="
body = "\n".join([f" โข {tx}" for tx in self.transaction_history])
footer = f"Current Available Balance: โน{self._balance:,.2f}\n" + "=" * 50
return f"{header}\n{body}\n{footer}"
# Run Banking System Demo:
acc = BankAccount("SBI-9021", "Balaji", 10000.0)
print(acc.deposit(5000.0))
print(acc.withdraw(3000.0))
print(acc.apply_interest())
print("\n" + acc.get_statement())
- Protected
_balancewith a read-only@propertyprevents direct unauthorized balance tampering. - Full audit logging via
self.transaction_history.
A complete library management system modeling books, borrowers, checkout duration, and book availability:
# =========================================================================
# PROJECT 2: LIBRARY CATALOG & BOOK LENDING SYSTEM
# =========================================================================
class Book:
def __init__(self, book_id, title, author):
self.book_id = book_id
self.title = title
self.author = author
self.is_borrowed = False
self.borrowed_by = None
def __str__(self):
status = f"Borrowed by {self.borrowed_by}" if self.is_borrowed else "Available โ
"
return f"[{self.book_id}] '{self.title}' by {self.author} ({status})"
class Library:
def __init__(self, name):
self.name = name
self.catalog = {} # book_id -> Book object
def add_book(self, book):
self.catalog[book.book_id] = book
print(f"๐ Added to library: {book.title}")
def lend_book(self, book_id, borrower_name):
book = self.catalog.get(book_id)
if not book:
return "โ Error: Book not found in catalog!"
if book.is_borrowed:
return f"โ '{book.title}' is currently borrowed by {book.borrowed_by}!"
book.is_borrowed = True
book.borrowed_by = borrower_name
return f"๐ Successfully issued '{book.title}' to {borrower_name}."
def return_book(self, book_id):
book = self.catalog.get(book_id)
if not book or not book.is_borrowed:
return "โ Error: Book is not currently on loan!"
borrower = book.borrowed_by
book.is_borrowed = False
book.borrowed_by = None
return f"โ
'{book.title}' returned successfully by {borrower}."
def display_catalog(self):
print(f"\n--- ๐๏ธ {self.name} Catalog ---")
for b in self.catalog.values():
print("โข", b)
# Run Library System Demo:
lib = Library("City Central Tech Library")
lib.add_book(Book("B101", "Fluent Python", "Luciano Ramalho"))
lib.add_book(Book("B102", "Clean Code", "Robert C. Martin"))
lib.add_book(Book("B103", "Designing Data-Intensive Apps", "Martin Kleppmann"))
lib.display_catalog()
print("\n" + lib.lend_book("B101", "Balaji"))
print(lib.lend_book("B101", "Alex")) # Test duplicate loan attempt
lib.display_catalog()
print("\n" + lib.return_book("B101"))
The Library class manages a collection of independent Book objects, encapsulating borrowing state cleanly.
A polymorphic corporate payroll system with hierarchical roles (Salaried, Hourly, and Commission-based Managers):
# =========================================================================
# PROJECT 3: ROLE-BASED EMPLOYEE PAYROLL SYSTEM
# =========================================================================
from abc import ABC, abstractmethod
class Employee(ABC):
def __init__(self, emp_id, name, department):
self.emp_id = emp_id
self.name = name
self.department = department
@abstractmethod
def calculate_pay(self):
"""Abstract method calculating monthly compensation."""
pass
def __str__(self):
return f"[{self.emp_id}] {self.name:12} ({self.department:10}) | Monthly Pay: โน{self.calculate_pay():,.2f}"
class SalariedEmployee(Employee):
def __init__(self, emp_id, name, department, monthly_salary):
super().__init__(emp_id, name, department)
self.monthly_salary = monthly_salary
def calculate_pay(self):
return self.monthly_salary
class HourlyEmployee(Employee):
def __init__(self, emp_id, name, department, hourly_rate, hours_worked):
super().__init__(emp_id, name, department)
self.hourly_rate = hourly_rate
self.hours_worked = hours_worked
def calculate_pay(self):
return self.hourly_rate * self.hours_worked
class Manager(SalariedEmployee):
def __init__(self, emp_id, name, department, monthly_salary, bonus):
super().__init__(emp_id, name, department, monthly_salary)
self.bonus = bonus
def calculate_pay(self):
return self.monthly_salary + self.bonus
# Payroll Processing Engine:
staff = [
SalariedEmployee("E101", "Balaji", "Engineering", 120000),
HourlyEmployee("E102", "Alex", "Design", 800, 160),
Manager("M101", "Chloe", "Management", 150000, 35000)
]
print("--- ๐ผ Monthly Corporate Payroll Summary ---")
total_payroll = 0
for emp in staff:
print(emp)
total_payroll += emp.calculate_pay()
print("=" * 60)
print(f"๐ฐ Total Company Payroll Outflow: โน{total_payroll:,.2f}")
The payroll loop calls emp.calculate_pay() uniformly without needing to know whether an employee is hourly or a salaried manager.
A complete e-commerce cart architecture with products, quantity management, coupon discounts, and tax computation:
# =========================================================================
# PROJECT 4: E-COMMERCE SHOPPING CART SYSTEM
# =========================================================================
class Item:
def __init__(self, item_id, name, unit_price):
self.item_id = item_id
self.name = name
self.unit_price = float(unit_price)
class CartItem:
def __init__(self, item, quantity=1):
self.item = item
self.quantity = quantity
@property
def subtotal(self):
return self.item.unit_price * self.quantity
class ShoppingCart:
def __init__(self, customer_name):
self.customer_name = customer_name
self.items = {} # item_id -> CartItem
def add_item(self, item, qty=1):
if item.item_id in self.items:
self.items[item.item_id].quantity += qty
else:
self.items[item.item_id] = CartItem(item, qty)
print(f"๐ Added {qty}x '{item.name}' to cart.")
def calculate_total(self, discount_percent=0.0, tax_percent=0.18):
gross = sum(ci.subtotal for ci in self.items.values())
discount = gross * (discount_percent / 100)
taxable = gross - discount
tax = taxable * tax_percent
final_bill = taxable + tax
return gross, discount, tax, final_bill
def print_invoice(self, coupon_discount=10):
gross, disc, tax, net = self.calculate_total(coupon_discount)
print("\n" + "=" * 48)
print(f"๐๏ธ INVOICE: {self.customer_name}'s Cart")
print("=" * 48)
for ci in self.items.values():
print(f"โข {ci.item.name:20} x{ci.quantity} @ โน{ci.item.unit_price:,.2f} = โน{ci.subtotal:,.2f}")
print("-" * 48)
print(f"Gross Subtotal: โน{gross:,.2f}")
print(f"Coupon ({coupon_discount}% off): -โน{disc:,.2f}")
print(f"GST Tax (18%): +โน{tax:,.2f}")
print(f"TOTAL PAYABLE: โน{net:,.2f}")
print("=" * 48)
# Run Shopping Cart Demo:
laptop = Item("ITM01", "Dell XPS 15", 145000)
mouse = Item("ITM02", "Logitech MX Master", 8500)
cart = ShoppingCart("Balaji")
cart.add_item(laptop, 1)
cart.add_item(mouse, 2)
cart.print_invoice(coupon_discount=10)
Separates the catalog Item from the dynamic order state CartItem and cart aggregation logic.
A comprehensive school academic administration engine modeling students, faculty teachers, course enrollments, and report card generation:
# =========================================================================
# PROJECT 5: SCHOOL MANAGEMENT SYSTEM
# =========================================================================
class Person:
def __init__(self, person_id, name, email):
self.person_id = person_id
self.name = name
self.email = email
class Teacher(Person):
def __init__(self, person_id, name, email, subject):
super().__init__(person_id, name, email)
self.subject = subject
def __str__(self):
return f"๐จโ๐ซ Prof. {self.name} (Subject: {self.subject})"
class Course:
def __init__(self, course_code, title, teacher):
self.course_code = course_code
self.title = title
self.teacher = teacher
self.enrolled_students = []
def enroll(self, student):
if student not in self.enrolled_students:
self.enrolled_students.append(student)
student.courses.append(self)
class Student(Person):
def __init__(self, person_id, name, email, grade_level):
super().__init__(person_id, name, email)
self.grade_level = grade_level
self.courses = []
self.grades = {} # course_code -> mark
def assign_grade(self, course_code, mark):
self.grades[course_code] = mark
def get_report_card(self):
lines = [f"๐ ACADEMIC REPORT: {self.name} (Grade: {self.grade_level})"]
for c in self.courses:
score = self.grades.get(c.course_code, "In Progress")
lines.append(f" โข {c.title:25} (Instructor: {c.teacher.name}) -> Score: {score}")
return "\n".join(lines)
# Run School System Demo:
prof_sharma = Teacher("T01", "Dr. Sharma", "sharma@school.edu", "Python & Algorithms")
prof_rao = Teacher("T02", "Dr. Rao", "rao@school.edu", "Computer Networks")
py_course = Course("CS101", "Advanced Python 3", prof_sharma)
net_course = Course("CS102", "Computer Networks", prof_rao)
student1 = Student("S101", "Balaji", "balaji@school.edu", "12th Standard")
py_course.enroll(student1)
net_course.enroll(student1)
student1.assign_grade("CS101", 96)
student1.assign_grade("CS102", 91)
print(student1.get_report_card())
Demonstrates clean relational mapping where Course holds enrolled students and Student maintains enrolled courses.
Always ensure instance data (like transaction histories, cart items, or student grade dictionaries) is initialized inside __init__ as an instance variable. Defining cart_items = [] at class level will share the exact same cart across all customers!
Instantiate an account in the BankAccount system, deposit โน5,000, withdraw โน1,200, apply annual interest, and print the generated statement.
acc = BankAccount("SBI-5544", "Ravi Kumar", 20000.0)
acc.deposit(8000.0)
acc.withdraw(2500.0)
acc.apply_interest()
print(acc.get_statement())
Q Why should I structure enterprise systems with OOP classes instead of raw dictionaries?
Classes provide strict data validation (via properties and type hints), encapsulate business rules alongside state, prevent key misspelling bugs, and allow polymorphic extensions without modifying callers.
Q How do I persist OOP objects to disk?
You can serialize objects to JSON using custom serializers, use the standard library "pickle" module, or map them to relational databases using ORM tools like SQLAlchemy / SQLModel.
Q What is the Single Responsibility Principle (SRP) in OOP design?
SRP states that a class should have only one reason to change (e.g. BankAccount handles balance rules, while StatementPrinter handles formatting and printing).