python

exercises

exercises.py🐍
"""
09 - OOP: Exercises
Practice object-oriented programming concepts.
"""

print("=" * 60)
print("OOP EXERCISES")
print("=" * 60)

# =============================================================================
# EXERCISE 1: Basic Class
# Create a 'Rectangle' class with width and height attributes
# Add methods: area(), perimeter(), is_square()
# =============================================================================
print("\n--- Exercise 1: Rectangle Class ---")

# Your code here:
class Rectangle:
    pass  # Replace with your implementation

# Test:
# rect = Rectangle(4, 5)
# print(f"Area: {rect.area()}")           # Should print 20
# print(f"Perimeter: {rect.perimeter()}") # Should print 18
# print(f"Is square: {rect.is_square()}") # Should print False
# square = Rectangle(5, 5)
# print(f"Is square: {square.is_square()}") # Should print True


# =============================================================================
# EXERCISE 2: Bank Account with Encapsulation
# Create a BankAccount class with:
# - private balance attribute
# - deposit(amount) method
# - withdraw(amount) method (with balance check)
# - get_balance() method
# =============================================================================
print("\n--- Exercise 2: Bank Account ---")

# Your code here:


# Test:
# account = BankAccount("Alice", 1000)
# print(account.deposit(500))    # Should return True
# print(account.get_balance())   # Should print 1500
# print(account.withdraw(2000))  # Should return False (insufficient)


# =============================================================================
# EXERCISE 3: Inheritance - Vehicles
# Create a Vehicle base class with make, model, year
# Create Car and Motorcycle subclasses
# Car should have num_doors, Motorcycle should have has_sidecar
# Each should have a description() method
# =============================================================================
print("\n--- Exercise 3: Vehicle Inheritance ---")

# Your code here:


# Test:
# car = Car("Toyota", "Camry", 2022, 4)
# bike = Motorcycle("Harley", "Sportster", 2021, False)
# print(car.description())
# print(bike.description())


# =============================================================================
# EXERCISE 4: Polymorphism - Shapes
# Create Shape base class with abstract area() method
# Create Circle, Rectangle, Triangle subclasses
# Create a function that calculates total area of any shapes list
# =============================================================================
print("\n--- Exercise 4: Polymorphism ---")

from abc import ABC, abstractmethod

# Your code here:


# Test:
# shapes = [Circle(5), Rectangle(4, 6), Triangle(3, 4)]
# print(f"Total area: {total_area(shapes)}")


# =============================================================================
# EXERCISE 5: Magic Methods - Fraction Class
# Create a Fraction class that supports:
# - __str__ for display
# - __add__ for addition
# - __mul__ for multiplication
# - __eq__ for equality comparison
# =============================================================================
print("\n--- Exercise 5: Fraction Class ---")

# Your code here:


# Test:
# f1 = Fraction(1, 2)
# f2 = Fraction(1, 4)
# print(f1)          # Should print "1/2"
# print(f1 + f2)     # Should print "3/4"
# print(f1 * f2)     # Should print "1/8"
# print(f1 == Fraction(2, 4))  # Should print True


# =============================================================================
# EXERCISE 6: Property Decorator - Person
# Create a Person class with:
# - first_name and last_name properties
# - full_name computed property
# - age property with validation (must be positive)
# - email property with basic validation
# =============================================================================
print("\n--- Exercise 6: Properties ---")

# Your code here:


# Test:
# person = Person("John", "Doe", 25, "john@example.com")
# print(person.full_name)  # John Doe
# person.age = -5          # Should raise ValueError


# =============================================================================
# EXERCISE 7: Class Methods - Factory Pattern
# Create a Date class with day, month, year
# Add class methods:
# - from_string(date_string) - parse "DD-MM-YYYY"
# - today() - return today's date
# =============================================================================
print("\n--- Exercise 7: Class Methods ---")

from datetime import date

# Your code here:


# Test:
# d1 = Date.from_string("25-12-2023")
# print(d1)  # Date: 25-12-2023
# d2 = Date.today()
# print(d2)


# =============================================================================
# EXERCISE 8: Static Methods - Validator
# Create a Validator class with static methods:
# - is_email(string) - check if valid email format
# - is_phone(string) - check if valid phone format
# - is_password_strong(string) - check password strength
# =============================================================================
print("\n--- Exercise 8: Static Methods ---")

# Your code here:


# Test:
# print(Validator.is_email("test@example.com"))  # True
# print(Validator.is_email("invalid"))           # False
# print(Validator.is_password_strong("Str0ng!Pass"))  # True


# =============================================================================
# EXERCISE 9: Composition - Library System
# Create these classes:
# - Book(title, author, isbn)
# - Member(name, member_id)
# - Library that manages books and members
# Library should have: add_book, add_member, borrow_book, return_book
# =============================================================================
print("\n--- Exercise 9: Library System ---")

# Your code here:


# Test:
# library = Library("City Library")
# book = Book("Python 101", "Author", "12345")
# member = Member("Alice", "M001")
# library.add_book(book)
# library.add_member(member)
# library.borrow_book("M001", "12345")


# =============================================================================
# EXERCISE 10: Iterator Class
# Create a Fibonacci iterator class that generates
# Fibonacci numbers up to a maximum value
# =============================================================================
print("\n--- Exercise 10: Iterator ---")

# Your code here:


# Test:
# for num in Fibonacci(100):
#     print(num, end=" ")
# Should print: 0 1 1 2 3 5 8 13 21 34 55 89


# =============================================================================
# SOLUTIONS (scroll down)
# =============================================================================
print("\n\n" + "=" * 60)
print("SOLUTIONS")
print("=" * 60)

# SOLUTION 1
print("\n--- Solution 1: Rectangle ---")

class RectangleSol:
    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)
    
    def is_square(self):
        return self.width == self.height

rect = RectangleSol(4, 5)
print(f"Area: {rect.area()}")
print(f"Perimeter: {rect.perimeter()}")
print(f"Is square: {rect.is_square()}")

# SOLUTION 2
print("\n--- Solution 2: Bank Account ---")

class BankAccountSol:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.__balance = balance
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return True
        return False
    
    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            return True
        return False
    
    def get_balance(self):
        return self.__balance

account = BankAccountSol("Alice", 1000)
print(f"Deposit 500: {account.deposit(500)}")
print(f"Balance: {account.get_balance()}")
print(f"Withdraw 2000: {account.withdraw(2000)}")

# SOLUTION 3
print("\n--- Solution 3: Vehicles ---")

class Vehicle:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
    
    def description(self):
        return f"{self.year} {self.make} {self.model}"

class Car(Vehicle):
    def __init__(self, make, model, year, num_doors):
        super().__init__(make, model, year)
        self.num_doors = num_doors
    
    def description(self):
        return f"{super().description()} ({self.num_doors} doors)"

class Motorcycle(Vehicle):
    def __init__(self, make, model, year, has_sidecar):
        super().__init__(make, model, year)
        self.has_sidecar = has_sidecar
    
    def description(self):
        sidecar = "with sidecar" if self.has_sidecar else "no sidecar"
        return f"{super().description()} ({sidecar})"

car = Car("Toyota", "Camry", 2022, 4)
bike = Motorcycle("Harley", "Sportster", 2021, False)
print(car.description())
print(bike.description())

# SOLUTION 4
print("\n--- Solution 4: Polymorphism ---")

class ShapeSol(ABC):
    @abstractmethod
    def area(self):
        pass

class CircleSol(ShapeSol):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2

class RectangleSol2(ShapeSol):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

class TriangleSol(ShapeSol):
    def __init__(self, base, height):
        self.base = base
        self.height = height
    
    def area(self):
        return 0.5 * self.base * self.height

def total_area(shapes):
    return sum(shape.area() for shape in shapes)

shapes = [CircleSol(5), RectangleSol2(4, 6), TriangleSol(3, 4)]
print(f"Total area: {total_area(shapes):.2f}")

# SOLUTION 5
print("\n--- Solution 5: Fraction ---")

from math import gcd

class Fraction:
    def __init__(self, numerator, denominator):
        common = gcd(numerator, denominator)
        self.numerator = numerator // common
        self.denominator = denominator // common
    
    def __str__(self):
        return f"{self.numerator}/{self.denominator}"
    
    def __add__(self, other):
        num = self.numerator * other.denominator + other.numerator * self.denominator
        den = self.denominator * other.denominator
        return Fraction(num, den)
    
    def __mul__(self, other):
        return Fraction(
            self.numerator * other.numerator,
            self.denominator * other.denominator
        )
    
    def __eq__(self, other):
        return self.numerator == other.numerator and self.denominator == other.denominator

f1 = Fraction(1, 2)
f2 = Fraction(1, 4)
print(f"f1: {f1}")
print(f"f1 + f2: {f1 + f2}")
print(f"f1 * f2: {f1 * f2}")
print(f"f1 == Fraction(2, 4): {f1 == Fraction(2, 4)}")

# SOLUTION 10
print("\n--- Solution 10: Fibonacci Iterator ---")

class Fibonacci:
    def __init__(self, max_value):
        self.max_value = max_value
    
    def __iter__(self):
        self.a = 0
        self.b = 1
        return self
    
    def __next__(self):
        if self.a > self.max_value:
            raise StopIteration
        current = self.a
        self.a, self.b = self.b, self.a + self.b
        return current

print("Fibonacci up to 100:")
for num in Fibonacci(100):
    print(num, end=" ")
print()

print("\n" + "=" * 60)
print("END OF EXERCISES")
print("=" * 60)
Exercises - Python Tutorial | DeepML