Low Level Design Programming in Python_ From Basic
Low Level Design Programming in Python_ From Basic
class Vehicle:
def __init__(self, brand, model, year):
self.brand = brand
self.model = model
self.year = year
self._engine_status = False # Protected attribute
def start_engine(self):
if not self._engine_status:
self._engine_status = True
return f"{self.brand} {self.model} engine started"
return "Engine already running"
def stop_engine(self):
if self._engine_status:
self._engine_status = False
return "Engine stopped"
return "Engine already off"
def __str__(self):
return f"{self.year} {self.brand} {self.model}"
# Creating objects
car = Vehicle("Toyota", "Camry", 2023)
print(car.start_engine()) # Toyota Camry engine started
class Car(Vehicle):
def __init__(self, brand, model, year, doors):
super().__init__(brand, model, year)
self.doors = doors
def honk(self):
return "Beep beep!"
class Motorcycle(Vehicle):
def __init__(self, brand, model, year, engine_cc):
super().__init__(brand, model, year)
self.engine_cc = engine_cc
def honk(self):
return "Vroom vroom!"
# Polymorphism in action
vehicles = [
Car("Honda", "Civic", 2023, 4),
Motorcycle("Yamaha", "R1", 2023, 1000)
]
Encapsulation[3][7]
class BankAccount:
def __init__(self, account_number, initial_balance=0):
self._account_number = account_number # Protected
self.__balance = initial_balance # Private
self._transaction_history = []
def get_balance(self):
return self.__balance
@property
def account_number(self):
return self._account_number
# Violates SRP
class BadUser:
def __init__(self, username, email):
self.username = username
self.email = email
def save_to_database(self):
# Database logic
pass
def send_email(self):
# Email logic
pass
# Follows SRP
class User:
def __init__(self, username, email):
self.username = username
self.email = email
class UserRepository:
def save_user(self, user):
# Database logic
print(f"Saving {user.username} to database")
class EmailService:
def send_welcome_email(self, user):
# Email logic
print(f"Sending welcome email to {user.email}")
2. Open/Closed Principle (OCP)
Software entities should be open for extension but closed for modification[10][8].
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount):
pass
class CreditCardProcessor(PaymentProcessor):
def process_payment(self, amount):
return f"Processing ${amount} via Credit Card"
class PayPalProcessor(PaymentProcessor):
def process_payment(self, amount):
return f"Processing ${amount} via PayPal"
class PaymentManager:
def __init__(self, processor: PaymentProcessor):
self.processor = processor
class Bird(ABC):
@abstractmethod
def make_sound(self):
pass
class FlyingBird(Bird):
@abstractmethod
def fly(self):
pass
def make_sound(self):
return "Generic bird sound"
class Sparrow(FlyingBird):
def fly(self):
return "Sparrow flying high"
def make_sound(self):
return "Chirp chirp"
class Penguin(Bird): # Penguins can't fly, so they don't inherit from FlyingBird
def make_sound(self):
return "Penguin sound"
def swim(self):
return "Penguin swimming"
# Violates ISP
class BadWorker(ABC):
@abstractmethod
def work(self):
pass
@abstractmethod
def eat(self):
pass
# Follows ISP
class Worker(ABC):
@abstractmethod
def work(self):
pass
class Eater(ABC):
@abstractmethod
def eat(self):
pass
def eat(self):
return "Human eating"
class EmailSender(ABC):
@abstractmethod
def send_email(self, recipient, message):
pass
class SMTPEmailSender(EmailSender):
def send_email(self, recipient, message):
return f"Sending via SMTP to {recipient}: {message}"
class SendGridEmailSender(EmailSender):
def send_email(self, recipient, message):
return f"Sending via SendGrid to {recipient}: {message}"
# Usage
smtp_sender = SMTPEmailSender()
notification_service = NotificationService(smtp_sender)
result = notification_service.notify_user("[email protected]", "Welcome!")
Creational Patterns
Factory Pattern[13][15]
class VehicleType(Enum):
CAR = "car"
MOTORCYCLE = "motorcycle"
TRUCK = "truck"
class Vehicle(ABC):
@abstractmethod
def start(self):
pass
@abstractmethod
def get_info(self):
pass
class Car(Vehicle):
def __init__(self, model):
self.model = model
def start(self):
return f"Car {self.model} engine started"
def get_info(self):
return f"Car: {self.model}"
class Motorcycle(Vehicle):
def __init__(self, model):
self.model = model
def start(self):
return f"Motorcycle {self.model} engine revved"
def get_info(self):
return f"Motorcycle: {self.model}"
class VehicleFactory:
@staticmethod
def create_vehicle(vehicle_type: VehicleType, model: str) -> Vehicle:
if vehicle_type == VehicleType.CAR:
return Car(model)
elif vehicle_type == VehicleType.MOTORCYCLE:
return Motorcycle(model)
else:
raise ValueError(f"Unknown vehicle type: {vehicle_type}")
# Usage
factory = VehicleFactory()
car = factory.create_vehicle(VehicleType.CAR, "Tesla Model 3")
motorcycle = factory.create_vehicle(VehicleType.MOTORCYCLE, "Harley Davidson")
Singleton Pattern[13][14]
class DatabaseConnection:
_instance = None
_connection = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(DatabaseConnection, cls).__new__(cls)
return cls._instance
def connect(self):
if not self._connection:
self._connection = "Connected to database"
print("Database connection established")
return self._connection
def get_connection(self):
return self._connection
# Usage
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True - same instance
db1.connect()
print(db2.get_connection()) # Connected to database
Behavioral Patterns
Observer Pattern[13][14]
class Subject:
def __init__(self):
self._observers = []
self._state = None
def notify(self):
for observer in self._observers:
observer.update(self._state)
class Observer(ABC):
@abstractmethod
def update(self, state):
pass
class EmailNotifier(Observer):
def update(self, state):
print(f"Email notification: State changed to {state}")
class SMSNotifier(Observer):
def update(self, state):
print(f"SMS notification: State changed to {state}")
# Usage
subject = Subject()
email_notifier = EmailNotifier()
sms_notifier = SMSNotifier()
subject.attach(email_notifier)
subject.attach(sms_notifier)
subject.set_state("Order Confirmed")
# Email notification: State changed to Order Confirmed
# SMS notification: State changed to Order Confirmed
Strategy Pattern[13][16]
class SortingStrategy(ABC):
@abstractmethod
def sort(self, data):
pass
class BubbleSortStrategy(SortingStrategy):
def sort(self, data):
data_copy = data.copy()
n = len(data_copy)
for i in range(n):
for j in range(0, n - i - 1):
if data_copy[j] > data_copy[j + 1]:
data_copy[j], data_copy[j + 1] = data_copy[j + 1], data_copy[j]
return data_copy
class QuickSortStrategy(SortingStrategy):
def sort(self, data):
if len(data) <= 1:
return data
pivot = data[len(data) // 2]
left = [x for x in data if x < pivot]
middle = [x for x in data if x == pivot]
right = [x for x in data if x > pivot]
return self.sort(left) + middle + self.sort(right)
class SortContext:
def __init__(self, strategy: SortingStrategy):
self._strategy = strategy
# Usage
data = [64, 34, 25, 12, 22, 11, 90]
context = SortContext(BubbleSortStrategy())
print(context.sort_data(data)) # Bubble sort result
context.set_strategy(QuickSortStrategy())
print(context.sort_data(data)) # Quick sort result
Class Design
class VehicleType(Enum):
MOTORCYCLE = "motorcycle"
CAR = "car"
TRUCK = "truck"
class SpotType(Enum):
MOTORCYCLE_SPOT = "motorcycle"
COMPACT_SPOT = "compact"
LARGE_SPOT = "large"
class SpotStatus(Enum):
AVAILABLE = "available"
OCCUPIED = "occupied"
RESERVED = "reserved"
class Vehicle:
def __init__(self, license_plate: str, vehicle_type: VehicleType):
self.license_plate = license_plate
self.vehicle_type = vehicle_type
def __str__(self):
return f"{self.vehicle_type.value}: {self.license_plate}"
class ParkingSpot:
def __init__(self, spot_id: str, spot_type: SpotType):
self.spot_id = spot_id
self.spot_type = spot_type
self.status = SpotStatus.AVAILABLE
self.vehicle = None
self.parked_time = None
class ParkingLevel:
def __init__(self, level_id: str):
self.level_id = level_id
self.spots = {}
self._init_spots()
def _init_spots(self):
# Initialize spots for the level
for i in range(10): # 10 motorcycle spots
spot_id = f"{self.level_id}-M{i}"
self.spots[spot_id] = ParkingSpot(spot_id, SpotType.MOTORCYCLE_SPOT)
class ParkingTicket:
def __init__(self, ticket_id: str, vehicle: Vehicle, spot: ParkingSpot):
self.ticket_id = ticket_id
self.vehicle = vehicle
self.spot = spot
self.issued_time = datetime.now()
self.paid_time = None
self.is_paid = False
class CashPayment(PaymentStrategy):
def process_payment(self, amount: float) -> bool:
print(f"Processing cash payment of ${amount:.2f}")
return True
class CardPayment(PaymentStrategy):
def __init__(self, card_number: str):
self.card_number = card_number
class ParkingLot:
def __init__(self, name: str, num_levels: int):
self.name = name
self.levels = {}
self.tickets = {}
# Initialize levels
for i in range(num_levels):
level_id = f"Level-{i+1}"
self.levels[level_id] = ParkingLevel(level_id)
ticket = self.tickets[ticket_id]
if not ticket.is_paid:
fee = ticket.calculate_fee()
if payment_strategy.process_payment(fee):
ticket.is_paid = True
ticket.paid_time = datetime.now()
else:
print("Payment failed")
return False
# Remove ticket
del self.tickets[ticket_id]
return True
def get_parking_status(self):
total_spots = 0
available_spots = 0
total_spots += level_total
available_spots += level_available
# Create vehicles
motorcycle = Vehicle("BIKE-123", VehicleType.MOTORCYCLE)
car1 = Vehicle("CAR-456", VehicleType.CAR)
car2 = Vehicle("CAR-789", VehicleType.CAR)
truck = Vehicle("TRUCK-101", VehicleType.TRUCK)
# Park vehicles
ticket1 = parking_lot.park_vehicle(motorcycle)
ticket2 = parking_lot.park_vehicle(car1)
ticket3 = parking_lot.park_vehicle(car2)
ticket4 = parking_lot.park_vehicle(truck)
# Check status
parking_lot.get_parking_status()
if ticket2:
parking_lot.exit_vehicle(ticket2.ticket_id, CardPayment("1234-5678-9012-3456"))
if __name__ == "__main__":
demo_parking_lot()
import sys
import gc
class MemoryEfficientClass:
__slots__ = ['name', 'value', 'timestamp'] # Reduces memory usage
@staticmethod
def get_memory_info():
return {
'objects': len(gc.get_objects()),
'garbage': len(gc.garbage)
}
@staticmethod
def trigger_gc():
collected = gc.collect()
print(f"Garbage collected {collected} objects")
def pop(self):
if self.size > 0:
item = self.buffer[self.head]
self.buffer[self.head] = None
self.head = (self.head + 1) % self.max_size
self.size -= 1
return item
return None
import unittest
from unittest.mock import Mock, patch
def test_initial_balance(self):
self.assertEqual(self.account.get_balance(), 1000)
def test_deposit_positive_amount(self):
result = self.account.deposit(500)
self.assertTrue(result)
self.assertEqual(self.account.get_balance(), 1500)
def test_deposit_negative_amount(self):
result = self.account.deposit(-100)
self.assertFalse(result)
self.assertEqual(self.account.get_balance(), 1000)
def test_withdraw_valid_amount(self):
result = self.account.withdraw(300)
self.assertTrue(result)
self.assertEqual(self.account.get_balance(), 700)
def test_withdraw_insufficient_funds(self):
result = self.account.withdraw(1500)
self.assertFalse(result)
self.assertEqual(self.account.get_balance(), 1000)
def test_transaction_history(self):
self.account.deposit(200)
self.account.withdraw(100)
history = self.account._transaction_history
self.assertEqual(len(history), 2)
self.assertIn("Deposited: $200", history[0])
self.assertIn("Withdrew: $100", history[1])
def test_successful_payment(self):
self.mock_payment_gateway.charge.return_value = {"status": "success", "transactio
self.assertTrue(result["success"])
self.assertEqual(result["transaction_id"], "TXN123")
self.mock_payment_gateway.charge.assert_called_once_with(100.0, "4111-1111-1111-1
def test_failed_payment(self):
self.mock_payment_gateway.charge.side_effect = Exception("Network error")
self.assertFalse(result["success"])
self.assertIn("error", result)
def test_full_parking_cycle(self):
# Park vehicle
ticket = self.parking_lot.park_vehicle(self.car)
self.assertIsNotNone(ticket)
self.assertEqual(ticket.vehicle.license_plate, "TEST-123")
# Exit vehicle
payment = CashPayment()
exit_success = self.parking_lot.exit_vehicle(ticket.ticket_id, payment)
self.assertTrue(exit_success)
if __name__ == '__main__':
unittest.main()
class OrderStatus(Enum):
PENDING = "pending"
CONFIRMED = "confirmed"
PROCESSING = "processing"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
class ProductCategory(Enum):
ELECTRONICS = "electronics"
CLOTHING = "clothing"
BOOKS = "books"
HOME = "home"
class RegularPricing(PricingStrategy):
def calculate_price(self, base_price: Decimal, quantity: int) -> Decimal:
return base_price * quantity
class BulkDiscountPricing(PricingStrategy):
def __init__(self, threshold: int, discount_percent: float):
self.threshold = threshold
self.discount_percent = discount_percent
class SeasonalPricing(PricingStrategy):
def __init__(self, discount_percent: float):
self.discount_percent = discount_percent
class EmailNotificationService(OrderObserver):
def update(self, order_id: str, old_status: OrderStatus, new_status: OrderStatus):
print(f"Email: Order {order_id} status changed from {old_status.value} to {new_st
class InventoryUpdateService(OrderObserver):
def __init__(self, inventory_manager):
self.inventory_manager = inventory_manager
class Order:
def __init__(self, customer_id: str):
self.order_id = str(uuid.uuid4())
self.customer_id = customer_id
self.items: List[OrderItem] = []
self.status = OrderStatus.PENDING
self.created_at = datetime.now()
self.total_amount = Decimal('0.00')
self._observers: List[OrderObserver] = []
def _calculate_total(self):
self.total_amount = sum(item.total_price for item in self.items)
@abstractmethod
def cancel(self, order: Order) -> bool:
pass
@abstractmethod
def ship(self, order: Order) -> bool:
pass
class PendingState(OrderState):
def confirm(self, order: Order) -> bool:
order.update_status(OrderStatus.CONFIRMED)
return True
class ConfirmedState(OrderState):
def confirm(self, order: Order) -> bool:
return False # Already confirmed
@abstractmethod
def undo(self):
pass
class AddItemCommand(Command):
def __init__(self, order: Order, product: Product, quantity: int):
self.order = order
self.product = product
self.quantity = quantity
self.executed = False
def execute(self):
if not self.executed:
self.order.add_item(self.product, self.quantity)
self.executed = True
def undo(self):
if self.executed:
self.order.remove_item(self.product.product_id)
self.executed = False
class OrderManager:
def __init__(self, inventory_manager):
self.orders: Dict[str, Order] = {}
self.inventory_manager = inventory_manager
self.email_service = EmailNotificationService()
self.inventory_service = InventoryUpdateService(inventory_manager)
order = self.orders[order_id]
# Reserve inventory
for item in order.items:
if not self.inventory_manager.reserve_stock(item.product.product_id, item.qua
print(f"Insufficient stock for {item.product.name}")
return False
# Confirm order
order.update_status(OrderStatus.CONFIRMED)
return True
class InventoryManager:
def __init__(self):
self.inventory: Dict[str, InventoryItem] = {}
# Demo
def demo_ecommerce_system():
# Initialize system
inventory_manager = InventoryManager()
order_manager = OrderManager(inventory_manager)
# Add to inventory
inventory_manager.add_product(laptop, 10)
inventory_manager.add_product(book, 50)
add_laptop_cmd.execute()
add_book_cmd.execute()
# Process order
success = order_manager.process_order(order.order_id)
print(f"Order processed: {success}")
if __name__ == "__main__":
demo_ecommerce_system()
Performance Considerations
@property
def data(self):
if self._data is None:
self._data = self._loader_func()
return self._data
# Connection pooling
class ConnectionPool:
def __init__(self, max_connections=10):
self.max_connections = max_connections
self._connections = []
self._in_use = set()
def get_connection(self):
if self._connections:
conn = self._connections.pop()
elif len(self._in_use) < self.max_connections:
conn = self._create_connection()
else:
raise Exception("No available connections")
self._in_use.add(conn)
return conn
def _create_connection(self):
return f"Connection-{len(self._in_use) + len(self._connections)}"
import logging
from functools import wraps
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Custom exceptions
class InsufficientFundsError(Exception):
def __init__(self, requested_amount, available_amount):
self.requested_amount = requested_amount
self.available_amount = available_amount
super().__init__(f"Insufficient funds: requested {requested_amount}, available {a
class InvalidProductError(Exception):
pass
@classmethod
def ok(cls, data):
return cls(success=True, data=data)
@classmethod
def error(cls, error):
return cls(success=False, error=error)
Conclusion
Low Level Design programming in Python requires mastering object-oriented principles, design
patterns, and system architecture concepts. Through hands-on projects like the parking lot and
e-commerce systems demonstrated above, you build practical skills in creating maintainable,
scalable, and robust applications.
The key to excellence in LLD is consistent practice with real-world projects, understanding the
trade-offs between different design choices, and continuously refining your approach based on
requirements and constraints. Remember that good design is not about applying every pattern
possible, but about choosing the right tools for the specific problem at hand[35].
Start with the fundamentals, practice regularly with coding projects, and gradually tackle more
complex system design challenges. The combination of theoretical knowledge and practical
implementation will prepare you for both technical interviews and real-world software
development challenges.