DEV Community

Cover image for Mastering Object-Oriented Programming (OOP) in Python
Alex Murithi
Alex Murithi

Posted on

Mastering Object-Oriented Programming (OOP) in Python

Object-Oriented Programming (OOP) organizes code into objects - bundles of data (attributes) and behavior (methods).
It makes programs modular, reusable, and easier to maintain.

1. Classes and Objects

i. Class
A class is a blueprint for creating objects. It defines attributes (data) and methods (functions).

class Car:
    make = "CrossOver SUV"
Enter fullscreen mode Exit fullscreen mode

ii. Object
An object is an instance of a class - like an actual car built from the blueprint.

2. The __init__ Method (Constructor)

When you create an object from a class, Python automatically calls a special method named __init__.
This method is known as the constructor, and its job is to initialize the object’s attributes - setting up its starting state.
It usually takes parameters that define the object’s initial data.
The first parameter is always self, which refers to the specific object being created.
Example1

class Car:
    make = "CrossOver SUV"

    def __init__(self, brand, color, max_speed, model):
        self.brand = brand
        self.color = color
        self.max_speed = max_speed
        self.model = model

    def start(self):
        print(f"The {self.brand} car has started")

    def stop(self, time):
        print(f"The {self.brand} car has stopped at {time}pm.")

    def acceleration(self, top_speed):
        print(f"The {self.brand} {self.model} can reach {top_speed} km/h")
Enter fullscreen mode Exit fullscreen mode

Creating Object

car1 = Car("Toyota", "White", 180, "Hilux")
car3 = Car("BMW", "Blue", 260, "X5")

car3.start()
car3.stop(4)
car3.acceleration(260)
print(car1.color)
print(car1.make)
Enter fullscreen mode Exit fullscreen mode

Output

The BMW car has started
The BMW car has stopped at 4pm.
The BMW X5 can reach 260 km/h
White
CrossOver SUV
Enter fullscreen mode Exit fullscreen mode

Example2: M-Pesa Account Class

class MpesaAccount:
    def __init__(self, name, phone_number, balance):
        self.name = name
        self.phone_number = phone_number
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount
        print(f"Deposited {amount}. New balance: {self.balance}")

    def withdrawal(self, amount):
        if amount > self.balance:
            print("Insufficient funds")
        else:
            self.balance -= amount
            print(f"Withdrew {amount}. New balance: {self.balance}")

    def check_balance(self):
        print(f"Balance: {self.balance}")
Enter fullscreen mode Exit fullscreen mode

Creating object and usage

alex_account = MpesaAccount("Alex", "+254712345678", 0)
alex_account.deposit(1000)
alex_account.check_balance()
alex_account.withdrawal(500)
Enter fullscreen mode Exit fullscreen mode

Output

Deposited 1000. New balance: 1000
Balance: 1000
Withdrew 500. New balance: 500
Enter fullscreen mode Exit fullscreen mode

3. The Four Pillars of OOP

i. Encapsulation
Protecting data by keeping attributes private and exposing only necessary methods.
Encapsulation means wrapping data and methods into a single unit (the class) and restricting direct access to internal details.
It’s like locking your valuables inside a safe - only authorized methods (keys) can access or modify them.

Key idea in the example below:
Keep attributes private using double underscores (__balance).
Provide public methods (deposit(), withdraw()) to interact safely.

Example

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.__balance = balance  # Private attribute

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Deposited {amount}. New balance: {self.__balance}")
        else:
            print("Deposit must be positive")

    def check_balance(self):
        print(f"Balance: {self.__balance}")
Enter fullscreen mode Exit fullscreen mode

Usage

acc = BankAccount("Alex", 3000)
acc.deposit(500)
acc.withdraw(1000)
print(acc.check_balance())
Enter fullscreen mode Exit fullscreen mode

Output

Deposited 500. New balance: 3500
Withdrew 1000. New balance: 2500
2500
Enter fullscreen mode Exit fullscreen mode

Why it matters:
Encapsulation prevents accidental or unauthorized changes to data, ensuring data integrity and security.

ii. Inheritance
Reuse attributes and methods from a parent class.
Inheritance allows one class (child) to reuse and extend the functionality of another class (parent).
It’s like a child inheriting traits from their parents but adding their own personality.

Key idea:
Use super() to call the parent’s constructor.
Add or override methods to customize behavior.
Example

class FarmAnimal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(f"{self.name} is eating")
Enter fullscreen mode Exit fullscreen mode

Child Class Example

class Cow(FarmAnimal):
    def __init__(self, name, age, milk_per_day):
        super().__init__(name, age)
        self.milk_per_day = milk_per_day

    def produce_milk(self):
        print(f"{self.name} produces {self.milk_per_day} litres per day")
Enter fullscreen mode Exit fullscreen mode

Usage

mukiri = Cow("Mukiri", 3, 250)
mukiri.eat()
mukiri.produce_milk()
Enter fullscreen mode Exit fullscreen mode

Output

Mukiri is eating
Mukiri produces 250 litres per day
Enter fullscreen mode Exit fullscreen mode

Why it matters:
Inheritance promotes code reuse, reduces duplication, and helps maintain a logical hierarchy - making large systems easier to manage.

iii. Polymorphism- One Interface, Many Forms
Same method name behaves differently depending on the object.
Polymorphism means “many forms” - different objects can respond to the same method call in their own way.
It’s like different musicians playing the same song on different instruments - same melody, unique sound.

Key idea:
Use the same method name across classes.
Each class defines its own version of the method.
Example

class Delivery:
    def delivery_status(self):
        print("Delivery is processing")

class Motorbike(Delivery):
    def delivery_status(self):
        print("Delivery is complete")
Enter fullscreen mode Exit fullscreen mode

Usage

d1 = Delivery()
d2 = Motorbike()
d1.delivery_status()
d2.delivery_status()
Enter fullscreen mode Exit fullscreen mode

Output

Delivery is processing
Delivery is complete
Enter fullscreen mode Exit fullscreen mode

Why it matters:
Polymorphism makes code flexible and scalable - you can add new classes without changing existing logic.

iv. Abstraction
Abstraction means showing only what’s necessary and hiding the rest.
It’s like driving a car - you use the steering wheel and pedals without worrying about how the engine works.

Key idea:
Use the abc module and @abstractmethod decorator.
Define abstract methods that must be implemented by child classes.
Example

from abc import ABC, abstractmethod

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

class Rectangle(Shape):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width
Enter fullscreen mode Exit fullscreen mode

Usage

rect = Rectangle(10, 5)
print(rect.area())
Enter fullscreen mode Exit fullscreen mode

Output

50
Enter fullscreen mode Exit fullscreen mode

Why it matters:
Abstraction simplifies complex systems by exposing only essential features - making code cleaner, easier to use, and less error-prone.

Comparison of the Four Pillars of OOP

Pillar Description Example in Python Key Benefit
Encapsulation Restrict direct access to attributes, expose via methods. Private __balance in BankAccount. Protects data integrity.
Inheritance Child class reuses parent’s attributes/methods. Cow(FarmAnimal) inherits eat(). Promotes code reuse.
Polymorphism Same method behaves differently across classes. delivery_status() in Delivery vs Motorbike. Increases flexibility.
Abstraction Hide implementation, expose only essentials. Shape with abstract area(). Simplifies usage.

Conclusion
Object-Oriented Programming transforms how we structure Python code - from simple scripts to scalable systems.

Top comments (0)