Python Object-Oriented Programming
Building with Classes and Objects
Explanation
OOP in Python
Object-Oriented Programming organizes code around objects (data) rather than functions (logic). Python makes OOP elegant and pythonic.
Think of a class as a blueprint for a house. Each house built from that blueprint is an object (instance). The blueprint defines what rooms exist (attributes) and what you can do in them (methods).
Key Concepts
- Class: Blueprint for creating objects
- Object/Instance: A specific thing created from a class
- Attribute: Data stored in an object
- Method: Function that belongs to a class
- Inheritance: Creating new classes based on existing ones
- Encapsulation: Hiding internal details
Python vs JavaScript OOP
// JavaScript
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
# Python
class User:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, {self.name}"
Demonstration
Example 1: Basic Class
class User:
# Class attribute (shared by all instances)
platform = "BigPoppaCode"
# Constructor (initializer)
def __init__(self, name, email):
# Instance attributes
self.name = name
self.email = email
self.active = True
# Instance method
def greet(self):
return f"Hello, I'm {self.name}!"
# Method that modifies state
def deactivate(self):
self.active = False
return f"{self.name} has been deactivated"
# String representation
def __str__(self):
status = "active" if self.active else "inactive"
return f"User({self.name}, {status})"
# Formal representation
def __repr__(self):
return f"User(name='{self.name}', email='{self.email}')"
# Creating instances
user1 = User("Arthur", "art@bpc.com")
user2 = User("Sarah", "sarah@example.com")
print(user1.greet()) # Hello, I'm Arthur!
print(user1.platform) # BigPoppaCode (class attribute)
print(user1) # User(Arthur, active)
print(user1.deactivate()) # Arthur has been deactivated
Example 2: Inheritance
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement")
def __str__(self):
return f"{self.__class__.__name__}: {self.name}"
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
def fetch(self):
return f"{self.name} is fetching the ball"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
def scratch(self):
return f"{self.name} is scratching the furniture"
# Using inheritance
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # Buddy says Woof!
print(cat.speak()) # Whiskers says Meow!
print(dog.fetch()) # Buddy is fetching the ball
# Polymorphism - same interface, different behavior
animals = [Dog("Rex"), Cat("Luna"), Dog("Max")]
for animal in animals:
print(animal.speak())
Example 3: Properties and Encapsulation
class BankAccount:
def __init__(self, owner, initial_balance=0):
self.owner = owner
self._balance = initial_balance # "Protected" (convention)
self._transactions = []
# Property getter
@property
def balance(self):
return self._balance
# Property setter with validation
@balance.setter
def balance(self, value):
if value < 0:
raise ValueError("Balance cannot be negative")
self._balance = value
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit must be positive")
self._balance += amount
self._transactions.append(f"+{amount}")
return self._balance
def withdraw(self, amount):
if amount > self._balance:
raise ValueError("Insufficient funds")
self._balance -= amount
self._transactions.append(f"-{amount}")
return self._balance
@property
def transaction_history(self):
return self._transactions.copy() # Return copy to prevent modification
# Class method - works on the class, not instances
@classmethod
def create_savings_account(cls, owner):
return cls(owner, initial_balance=100) # Bonus for savings
# Static method - doesn't need class or instance
@staticmethod
def validate_amount(amount):
return amount > 0
# Using the class
account = BankAccount("Arthur", 1000)
print(account.balance) # 1000 (using property getter)
account.deposit(500)
account.withdraw(200)
print(account.balance) # 1300
print(account.transaction_history) # ['+500', '-200']
# Class method usage
savings = BankAccount.create_savings_account("Sarah")
print(savings.balance) # 100
Key Takeaways:
__init__is the constructorselfrefers to the instance (likethisin JS)- Use
@propertyfor computed/validated attributes - Single underscore
_nameindicates "protected" (convention) - Double underscore
__nameenables name mangling (true privacy)
Imitation
Challenge 1: Create a Product Class
Task: Create a Product class with name, price, and quantity. Include a method to calculate total value and apply discounts.
Solution
class Product:
def __init__(self, name, price, quantity=1):
self.name = name
self._price = price
self.quantity = quantity
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("Price cannot be negative")
self._price = value
@property
def total_value(self):
return self._price * self.quantity
def apply_discount(self, percent):
discount = self._price * (percent / 100)
self._price -= discount
return self._price
def __str__(self):
return f"{self.name}: ${self._price} x {self.quantity}"
Challenge 2: Implement a Shape Hierarchy
Task: Create Shape base class with Circle and Rectangle subclasses. Each should calculate area and perimeter.
Solution
import math
class Shape:
def area(self):
raise NotImplementedError
def perimeter(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
def perimeter(self):
return 2 * math.pi * self.radius
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
Practice
Exercise 1: Library System
Difficulty: Intermediate
Create classes for a library system:
Bookwith title, author, isbn, available statusLibrarythat manages books (add, remove, borrow, return)Memberwho can borrow books
Exercise 2: E-commerce Cart
Difficulty: Advanced
Build a shopping cart system:
Productclass with inventory trackingCartclass that holds items and calculates totalsOrderclass created from cart with status tracking
Summary
What you learned:
- Creating classes with
__init__ - Instance vs class attributes
- Inheritance and polymorphism
- Properties for encapsulation
- Class and static methods
Next Steps:
- Read: Python APIs
- Practice: Refactor procedural code to OOP
- Build: Create a game with OOP principles
