Object-Oriented Programming β
ποΈ Classes and Objects β
Creating a Class β
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, my name is {self.name}"
def have_birthday(self):
self.age += 1
return f"Happy birthday! I'm now {self.age} years old"
# Creating objects (instances)
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print(person1.greet()) # Hello, my name is Alice
print(person2.have_birthday()) # Happy birthday! I'm now 31 years oldInstance vs Class Variables β
python
class Student:
# Class variable (shared by all instances)
school = "Python Academy"
def __init__(self, name, grade):
# Instance variables (unique to each instance)
self.name = name
self.grade = grade
def study(self):
return f"{self.name} is studying at {self.school}"
student1 = Student("Alice", "A")
student2 = Student("Bob", "B")
print(student1.study()) # Alice is studying at Python Academy
print(Student.school) # Python Academyπ Encapsulation β
Private Attributes β
python
class BankAccount:
def __init__(self, account_number, initial_balance=0):
self.account_number = account_number
self._balance = initial_balance # Protected attribute
self.__pin = None # Private attribute
def deposit(self, amount):
if amount > 0:
self._balance += amount
return f"Deposited ${amount}. New balance: ${self._balance}"
return "Invalid deposit amount"
def withdraw(self, amount):
if 0 < amount <= self._balance:
self._balance -= amount
return f"Withdrew ${amount}. New balance: ${self._balance}"
return "Invalid withdrawal amount or insufficient funds"
def get_balance(self):
return self._balance
def set_pin(self, pin):
self.__pin = pin
def _validate_pin(self, pin):
return self.__pin == pin
account = BankAccount("12345", 1000)
print(account.deposit(500)) # Deposited $500. New balance: $1500
print(account.get_balance()) # 1500Properties (Getters and Setters) β
python
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value <= 0:
raise ValueError("Radius must be positive")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
@property
def circumference(self):
return 2 * 3.14159 * self._radius
circle = Circle(5)
print(circle.radius) # 5
print(circle.area) # 78.53975
circle.radius = 10
print(circle.area) # 314.159𧬠Inheritance β
Basic Inheritance β
python
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def speak(self):
return f"{self.name} makes a sound"
def info(self):
return f"{self.name} is a {self.species}"
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "Dog")
self.breed = breed
def speak(self):
return f"{self.name} barks"
def fetch(self):
return f"{self.name} fetches the ball"
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name, "Cat")
self.color = color
def speak(self):
return f"{self.name} meows"
def purr(self):
return f"{self.name} purrs contentedly"
# Usage
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers", "Orange")
print(dog.speak()) # Buddy barks
print(cat.speak()) # Whiskers meows
print(dog.info()) # Buddy is a Dog
print(dog.fetch()) # Buddy fetches the ballMultiple Inheritance β
python
class Flyable:
def fly(self):
return "Flying through the air"
class Swimmable:
def swim(self):
return "Swimming in water"
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name, "Duck")
def speak(self):
return f"{self.name} quacks"
duck = Duck("Donald")
print(duck.speak()) # Donald quacks
print(duck.fly()) # Flying through the air
print(duck.swim()) # Swimming in waterπ Polymorphism β
Method Overriding β
python
class Shape:
def area(self):
raise NotImplementedError("Subclass must implement area method")
def perimeter(self):
raise NotImplementedError("Subclass must implement perimeter method")
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)
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
# Polymorphism in action
shapes = [Rectangle(4, 5), Circle(3), Rectangle(2, 8)]
for shape in shapes:
print(f"Area: {shape.area():.2f}")
print(f"Perimeter: {shape.perimeter():.2f}")
print()π§ Special Methods (Magic Methods) β
Common Magic Methods β
python
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"'{self.title}' by {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
def __len__(self):
return self.pages
def __eq__(self, other):
if isinstance(other, Book):
return self.title == other.title and self.author == other.author
return False
def __lt__(self, other):
if isinstance(other, Book):
return self.pages < other.pages
return NotImplemented
def __add__(self, other):
if isinstance(other, Book):
return self.pages + other.pages
return NotImplemented
book1 = Book("Python Programming", "John Doe", 300)
book2 = Book("Data Science", "Jane Smith", 450)
print(str(book1)) # 'Python Programming' by John Doe
print(repr(book1)) # Book('Python Programming', 'John Doe', 300)
print(len(book1)) # 300
print(book1 < book2) # True
print(book1 + book2) # 750π Class Methods and Static Methods β
python
class Employee:
company = "Tech Corp"
employee_count = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.employee_count += 1
# Instance method
def get_info(self):
return f"{self.name} earns ${self.salary}"
# Class method
@classmethod
def get_employee_count(cls):
return cls.employee_count
@classmethod
def from_string(cls, employee_str):
name, salary = employee_str.split('-')
return cls(name, int(salary))
# Static method
@staticmethod
def is_workday(day):
return day.lower() not in ['saturday', 'sunday']
# Usage
emp1 = Employee("Alice", 70000)
emp2 = Employee("Bob", 80000)
print(Employee.get_employee_count()) # 2
# Create employee from string
emp3 = Employee.from_string("Charlie-75000")
print(emp3.get_info()) # Charlie earns $75000
# Static method usage
print(Employee.is_workday("Monday")) # True
print(Employee.is_workday("Saturday")) # FalseποΈ Abstract Classes β
python
from abc import ABC, abstractmethod
class Vehicle(ABC):
def __init__(self, brand, model):
self.brand = brand
self.model = model
@abstractmethod
def start_engine(self):
pass
@abstractmethod
def stop_engine(self):
pass
def info(self):
return f"{self.brand} {self.model}"
class Car(Vehicle):
def start_engine(self):
return "Car engine started with key"
def stop_engine(self):
return "Car engine stopped"
class Motorcycle(Vehicle):
def start_engine(self):
return "Motorcycle engine started with button"
def stop_engine(self):
return "Motorcycle engine stopped"
# Usage
car = Car("Toyota", "Camry")
motorcycle = Motorcycle("Honda", "CBR")
print(car.info()) # Toyota Camry
print(car.start_engine()) # Car engine started with key
print(motorcycle.start_engine()) # Motorcycle engine started with buttonπ Practice Examples β
Example 1: Library Management System β
python
class Book:
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.is_checked_out = False
self.checked_out_by = None
def __str__(self):
return f"'{self.title}' by {self.author}"
class Member:
def __init__(self, name, member_id):
self.name = name
self.member_id = member_id
self.checked_out_books = []
def check_out_book(self, book):
if not book.is_checked_out:
book.is_checked_out = True
book.checked_out_by = self
self.checked_out_books.append(book)
return f"{self.name} checked out {book}"
return f"{book} is already checked out"
def return_book(self, book):
if book in self.checked_out_books:
book.is_checked_out = False
book.checked_out_by = None
self.checked_out_books.remove(book)
return f"{self.name} returned {book}"
return f"{book} was not checked out by {self.name}"
class Library:
def __init__(self, name):
self.name = name
self.books = []
self.members = []
def add_book(self, book):
self.books.append(book)
def add_member(self, member):
self.members.append(member)
def find_book(self, title):
for book in self.books:
if book.title.lower() == title.lower():
return book
return None
def list_available_books(self):
return [book for book in self.books if not book.is_checked_out]
# Usage
library = Library("City Library")
book1 = Book("Python Programming", "John Doe", "123456")
book2 = Book("Data Science", "Jane Smith", "789012")
library.add_book(book1)
library.add_book(book2)
member1 = Member("Alice", "M001")
library.add_member(member1)
print(member1.check_out_book(book1)) # Alice checked out 'Python Programming' by John Doe
print(len(library.list_available_books())) # 1Example 2: Game Character System β
python
class Character:
def __init__(self, name, health, attack_power):
self.name = name
self.max_health = health
self.health = health
self.attack_power = attack_power
self.level = 1
def attack(self, target):
damage = self.attack_power
target.take_damage(damage)
return f"{self.name} attacks {target.name} for {damage} damage"
def take_damage(self, damage):
self.health -= damage
if self.health <= 0:
self.health = 0
return f"{self.name} has been defeated"
return f"{self.name} takes {damage} damage, health: {self.health}"
def heal(self, amount):
self.health = min(self.max_health, self.health + amount)
return f"{self.name} heals for {amount}, health: {self.health}"
def is_alive(self):
return self.health > 0
class Warrior(Character):
def __init__(self, name):
super().__init__(name, health=120, attack_power=25)
self.armor = 10
def defend(self):
return f"{self.name} raises shield, reducing next damage by 50%"
def take_damage(self, damage):
reduced_damage = max(1, damage - self.armor)
return super().take_damage(reduced_damage)
class Mage(Character):
def __init__(self, name):
super().__init__(name, health=80, attack_power=15)
self.mana = 50
def cast_spell(self, target):
if self.mana >= 20:
self.mana -= 20
spell_damage = self.attack_power * 2
target.take_damage(spell_damage)
return f"{self.name} casts fireball on {target.name} for {spell_damage} damage"
return f"{self.name} doesn't have enough mana"
# Usage
warrior = Warrior("Sir Lancelot")
mage = Mage("Gandalf")
print(warrior.attack(mage)) # Sir Lancelot attacks Gandalf for 25 damage
print(mage.cast_spell(warrior)) # Gandalf casts fireball on Sir Lancelot for 30 damage
print(warrior.health) # 105 (120 - 30 + 10 armor = 105)π― Key Takeaways β
- Classes are blueprints for creating objects
- Objects are instances of classes with their own data
- Encapsulation hides internal details and provides controlled access
- Inheritance allows classes to inherit from other classes
- Polymorphism enables objects to be treated as instances of their parent class
- Magic methods customize object behavior for built-in operations
- Class methods operate on the class itself, not instances
- Static methods are utility functions that belong to the class
- Abstract classes define interfaces that subclasses must implement
- OOP promotes code reusability, modularity, and maintainability
Continue to: Built-in Functions β