Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
662 changes: 662 additions & 0 deletions architecture/oop/index.md

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions starter_kit/oop/abstraction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# ============================================
# ABSTRACTION
# ============================================

print("=" * 60)
print("ABSTRACTION - Hiding Complexity")
print("=" * 60)

from abc import ABC, abstractmethod

# Abstract base class
print("\n1️⃣ ABSTRACT BASE CLASS")
print("-" * 60)

class Animal(ABC):
"""Abstract animal class"""

def __init__(self, name):
self.name = name

@abstractmethod
def speak(self):
"""Abstract method - must be implemented by child classes"""
pass

@abstractmethod
def move(self):
"""Abstract method"""
pass

class Dog(Animal):
"""Concrete dog class"""

def speak(self):
return f"{self.name} barks: Woof!"

def move(self):
return f"{self.name} runs on four legs"

class Bird(Animal):
"""Concrete bird class"""

def speak(self):
return f"{self.name} chirps: Tweet!"

def move(self):
return f"{self.name} flies in the sky"

# Cannot create instance of abstract class
# animal = Animal("Generic") # ❌ Error!

# Can create instances of concrete classes
dog = Dog("Buddy")
bird = Bird("Tweety")

print(dog.speak())
print(dog.move())
print(bird.speak())
print(bird.move())

# Abstract class with concrete methods
print("\n2️⃣ ABSTRACT CLASS WITH CONCRETE METHODS")
print("-" * 60)

class Vehicle(ABC):
"""Abstract vehicle class"""

def __init__(self, brand):
self.brand = brand

@abstractmethod
def start(self):
"""Abstract method"""
pass

def stop(self):
"""Concrete method - shared by all vehicles"""
return f"{self.brand} stopped"

class Car(Vehicle):
"""Concrete car class"""

def start(self):
return f"{self.brand} car engine started"

class Bike(Vehicle):
"""Concrete bike class"""

def start(self):
return f"{self.brand} bike engine started"

car = Car("Toyota")
bike = Bike("Honda")

print(car.start())
print(car.stop())
print(bike.start())
print(bike.stop())

# Interface-like abstract class
print("\n3️⃣ INTERFACE-LIKE ABSTRACT CLASS")
print("-" * 60)

class PaymentProcessor(ABC):
"""Payment processor interface"""

@abstractmethod
def process_payment(self, amount):
"""Process payment"""
pass

@abstractmethod
def refund(self, amount):
"""Process refund"""
pass

class CreditCardProcessor(PaymentProcessor):
"""Credit card payment processor"""

def process_payment(self, amount):
return f"Processing ₹{amount} via Credit Card"

def refund(self, amount):
return f"Refunding ₹{amount} to Credit Card"

class UPIProcessor(PaymentProcessor):
"""UPI payment processor"""

def process_payment(self, amount):
return f"Processing ₹{amount} via UPI"

def refund(self, amount):
return f"Refunding ₹{amount} to UPI"

def make_payment(processor, amount):
"""Function that works with any payment processor"""
print(processor.process_payment(amount))

cc = CreditCardProcessor()
upi = UPIProcessor()

make_payment(cc, 1000)
make_payment(upi, 500)

# Real-world example: Database abstraction
print("\n4️⃣ REAL-WORLD EXAMPLE: DATABASE")
print("-" * 60)

class Database(ABC):
"""Abstract database class"""

@abstractmethod
def connect(self):
pass

@abstractmethod
def execute(self, query):
pass

@abstractmethod
def close(self):
pass

class MySQLDatabase(Database):
"""MySQL implementation"""

def connect(self):
return "Connected to MySQL"

def execute(self, query):
return f"Executing in MySQL: {query}"

def close(self):
return "MySQL connection closed"

class PostgreSQLDatabase(Database):
"""PostgreSQL implementation"""

def connect(self):
return "Connected to PostgreSQL"

def execute(self, query):
return f"Executing in PostgreSQL: {query}"

def close(self):
return "PostgreSQL connection closed"

def run_query(db, query):
"""Run query on any database"""
print(db.connect())
print(db.execute(query))
print(db.close())

mysql = MySQLDatabase()
postgres = PostgreSQLDatabase()

print("MySQL:")
run_query(mysql, "SELECT * FROM users")

print("\nPostgreSQL:")
run_query(postgres, "SELECT * FROM users")

print()
147 changes: 147 additions & 0 deletions starter_kit/oop/class-basics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# ============================================
# CLASS BASICS
# ============================================

print("=" * 60)
print("CLASS BASICS - Introduction to OOP")
print("=" * 60)

# Simple class
print("\n1️⃣ SIMPLE CLASS")
print("-" * 60)

class Dog:
"""A simple Dog class"""
pass

# Create object (instance)
my_dog = Dog()
print(f"Created dog object: {my_dog}")

# Class with attributes
print("\n2️⃣ CLASS WITH ATTRIBUTES")
print("-" * 60)

class Person:
"""Person class with attributes"""

def __init__(self, name, age):
"""Constructor - runs when object is created"""
self.name = name # Instance attribute
self.age = age

# Create objects
person1 = Person("Ragul", 25)
person2 = Person("Alice", 30)

print(f"Person 1: {person1.name}, Age: {person1.age}")
print(f"Person 2: {person2.name}, Age: {person2.age}")

# Class with methods
print("\n3️⃣ CLASS WITH METHODS")
print("-" * 60)

class Calculator:
"""Calculator class with methods"""

def add(self, a, b):
"""Add two numbers"""
return a + b

def subtract(self, a, b):
"""Subtract two numbers"""
return a - b

calc = Calculator()
print(f"10 + 5 = {calc.add(10, 5)}")
print(f"10 - 5 = {calc.subtract(10, 5)}")

# Complete class example
print("\n4️⃣ COMPLETE CLASS EXAMPLE")
print("-" * 60)

class BankAccount:
"""Bank account class"""

def __init__(self, owner, balance=0):
"""Initialize account"""
self.owner = owner
self.balance = balance

def deposit(self, amount):
"""Deposit money"""
self.balance += amount
print(f"Deposited ₹{amount}. New balance: ₹{self.balance}")

def withdraw(self, amount):
"""Withdraw money"""
if amount > self.balance:
print("Insufficient funds!")
else:
self.balance -= amount
print(f"Withdrew ₹{amount}. New balance: ₹{self.balance}")

def get_balance(self):
"""Get current balance"""
return self.balance

# Create account
account = BankAccount("Ragul", 1000)
print(f"Account owner: {account.owner}")
print(f"Initial balance: ₹{account.get_balance()}")

account.deposit(500)
account.withdraw(200)
account.withdraw(2000) # Insufficient funds

# Class vs Instance attributes
print("\n5️⃣ CLASS VS INSTANCE ATTRIBUTES")
print("-" * 60)

class Student:
"""Student class"""

# Class attribute (shared by all instances)
school = "ABC School"

def __init__(self, name, grade):
# Instance attributes (unique to each instance)
self.name = name
self.grade = grade

student1 = Student("Alice", "A")
student2 = Student("Bob", "B")

print(f"Student 1: {student1.name}, Grade: {student1.grade}, School: {student1.school}")
print(f"Student 2: {student2.name}, Grade: {student2.grade}, School: {student2.school}")

# Change class attribute
Student.school = "XYZ School"
print(f"\nAfter changing school:")
print(f"Student 1 school: {student1.school}")
print(f"Student 2 school: {student2.school}")

# String representation
print("\n6️⃣ STRING REPRESENTATION (__str__ and __repr__)")
print("-" * 60)

class Book:
"""Book class with string representation"""

def __init__(self, title, author):
self.title = title
self.author = author

def __str__(self):
"""User-friendly string representation"""
return f"'{self.title}' by {self.author}"

def __repr__(self):
"""Developer-friendly representation"""
return f"Book(title='{self.title}', author='{self.author}')"

book = Book("Python Basics", "John Doe")
print(f"Using print: {book}") # Calls __str__
print(f"Using repr: {repr(book)}") # Calls __repr__

print()
Loading