Courses/Python Mastery/Module 9: Object-Oriented Python
Module 9 · Lesson 635 minBeginner🧪 Practice Session

🧪 Practice: OOP

Lesson goal
Build a BankAccount, a Student class, and an Animal family tree with inheritance.

🧪 Practice: OOP

Six exercises that turn class theory into class instinct. Solutions at the bottom.

Exercise 1 — The BankAccount

Create a BankAccount class with owner and balance (default 0). Methods: deposit(amount) (reject negatives by raising ValueError), withdraw(amount) (reject if insufficient funds), __str__ showing "Owner: ₹balance".

code
acc = BankAccount("Aarav")
acc.deposit(500)
acc.withdraw(200)
print(acc)                 # Aarav: ₹300
acc.withdraw(1000)         # ValueError!

Exercise 2 — The Rectangle

A Rectangle class with width and height. Add methods area(), perimeter(), and is_square() (returns a bool).

code
r = Rectangle(4, 4)
print(r.area())        # 16
print(r.is_square())   # True

Exercise 3 — The Animal family (inheritance)

Base class Animal with __init__(name) and speak() printing "...". Create Dog and Cat children that override speak(). Create a list of all three and loop it, calling speak on each.

code
# Expected:
# ...
# Rocky says Woof!
# Whiskers says Meow!

Exercise 4 — Dataclass book

Rewrite this as a @dataclass with generated init/eq/repr, plus one method is_long() (True if pages > 300):

code
class Book:
    def __init__(self, title, author, pages):
        self.title = title
        self.author = author
        self.pages = pages

Exercise 5 — The library (objects in containers)

Using your Book dataclass, create a Library class holding a list of books, with add_book(book) and find_by_author(author) returning matching books.

Exercise 6 — Fix the broken class

code
class Counter:
    def __init__(count):
        count = 0

    def increment():
        count += 1

c = Counter()
c.increment()      # crashes!
print(c.count)     # and this too

Solutions

Exercise 1:

code
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Deposit must be positive")
        self.balance += amount

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient funds")
        self.balance -= amount

    def __str__(self):
        return f"{self.owner}: ₹{self.balance}"

acc = BankAccount("Aarav")
acc.deposit(500)
acc.withdraw(200)
print(acc)

Exercise 2:

code
class Rectangle:
    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

Exercise 3:

code
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("...")

class Dog(Animal):
    def speak(self):
        print(f"{self.name} says Woof!")

class Cat(Animal):
    def speak(self):
        print(f"{self.name} says Meow!")

zoo = [Animal("Mystery"), Dog("Rocky"), Cat("Whiskers")]
for animal in zoo:
    animal.speak()

(Notice the loop doesn't care which type each animal is — polymorphism: same call, right behavior.)

Exercise 4:

code
from dataclasses import dataclass

@dataclass
class Book:
    title: str
    author: str
    pages: int

    def is_long(self):
        return self.pages > 300

Exercise 5:

code
@dataclass
class Library:
    books: list = field(default_factory=list)

    def add_book(self, book):
        self.books.append(book)

    def find_by_author(self, author):
        return [b for b in self.books if b.author == author]

lib = Library()
lib.add_book(Book("Python Basics", "Galvan", 250))
lib.add_book(Book("Advanced Python", "Galvan", 400))
print(lib.find_by_author("Galvan"))

(That list comprehension inside find_by_author is a preview of Module 10.)

Exercise 6:

code
class Counter:
    def __init__(self):          # self was missing
        self.count = 0           # count = 0 created a LOCAL, not an attribute

    def increment(self):         # self was missing here too
        self.count += 1          # and must go through self

c = Counter()
c.increment()
print(c.count)     # 1

Both bugs were self bugs — the exact mistakes Module 9 predicted.


✅ Module 9 Checkpoint

Classes built, inherited, dataclassed, and debugged. You can now read the class-based code inside every framework and library you'll ever install.

Next module: Power Tools — comprehensions, generators, and the standard library.