DEV Community

Lameck Odhiambo
Lameck Odhiambo

Posted on

Python Object Oriented Programming(OOP)

Object Oriented Programming(OOP) is a way of writing programs by modelling real-world things as "objects". Instead of writing code as a long list of instructions that act on separate variables, OOP groups related data(attributes) and behaviour (methods) together into a single object called an object.

Real world Analogy
Think about a real world car.

A car has attributes(color, fuel type, brand, max-speed) it can do things like(accelerate, braking, honk).
In OOP we would create a Car object that bundles those attributes and behaviours together, instead of tracking color, brand, fuel type, max-speed acceleration,braking etc as disconnected variables.

Four Pillars of OOP

  • Encapsulation
  • Inheritance
  • Polymorphism
  • Abstraction

Classes and Object

What is a class?

  • A class is a blueprint or template for creating objects. It defines what attributes(data) and methods(functions) the objects created from it will have. Note: A class does not hold any actual data itself, it only describes the shape that objects of that type will take.

a. Class Attributes
Defined directly inside the class body, outside of any method(function). They are shared by all objects of that class unless an individual object overrides them.

Example

class Dog:
    species = "Canis familiaris" # class attribute (Shared by all Dogs)
Enter fullscreen mode Exit fullscreen mode

b. Instance attributes
Defined inside init(or any method) using self.attribute_name = value.
Each object gets its own independent copy.

class Dog:
    def __init__(self, name, breed):
        self.name = name # Instance attribute, unique per dog/instance of the class
        self.breed = breed # Instance attribute, unique per dog/instance of the class
Enter fullscreen mode Exit fullscreen mode

Methods

  • Methods are functions defined inside a class. They define/describe the behaviours an object can perform. Like init, regular methods take 'self' as their first parameter so they can access and modify the object's own attributes.
class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def bark(self):
        print(f"{self.name} says: Woof!")

    def play(self, minutes):
        print(f"{self.name} played for {minutes} minutes")

    def fact(self, top_speed):
        print(f"The dog '{self.name}' of breed '{self.breed}' can reach a maximum speed of {top_speed}km/h.")
Enter fullscreen mode Exit fullscreen mode
dog1 = Dog("Bosco", "African Shepherd")

dog1.bark()
dog1.play(30)
dog1.fact(72)
Enter fullscreen mode Exit fullscreen mode

Output:

Bosco says: Woof!
Bosco played for 30 minutes
The dog 'Bosco' of breed 'African Shepherd' can reach a maximum speed of 72km/h.
Enter fullscreen mode Exit fullscreen mode
# German Shepherd Instance
german_shepherd = Dog("Max", "German Shepherd")

german_shepherd.bark()
german_shepherd.play(60)
german_shepherd.fact(56)
Enter fullscreen mode Exit fullscreen mode

Output:

Max says: Woof!
Max played for 60 minutes
The dog 'Max' of breed 'German Shepherd' can reach a maximum speed of 56km/h.
Enter fullscreen mode Exit fullscreen mode

MPESA Example

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

    def deposit(self, amount):
        self.balance += amount # self.balance = self.balance + amount
        print(f"You have successfully deposited KES {amount}, new acc balance KES {self.balance}")

    def withdraw(self, amount):
        self.balance -= amount # self.balance = self.balance - amount
        print(f"You have successfully withdrawn KES {amount}, new acc balance KES {self.balance}")

    def check_balance(self):
        print(f"Balance: KES {self.balance}")
Enter fullscreen mode Exit fullscreen mode
emmanuel_acc = MpesaAccount("+254712345678", "Emmanuel", 0)
emmanuel_acc.deposit(500)
Enter fullscreen mode Exit fullscreen mode

Output:

You have successfully deposited KES 500, new acc balance KES 500
Enter fullscreen mode Exit fullscreen mode
emmanuel_acc.withdraw(250)
Enter fullscreen mode Exit fullscreen mode

Output:

You have successfully withdrawn KES 250, new acc balance KES 250
Enter fullscreen mode Exit fullscreen mode
emmanuel_acc.check_balance()
Enter fullscreen mode Exit fullscreen mode

Output:

Balance: KES 250
Enter fullscreen mode Exit fullscreen mode

Four Pillars Of Object Oriented Programming

1. Encapsulation

  • Encapsulation means bundling an object's data(attributes) and the methods that operate on that data into a single class, and restricting direct access to some of that data from outside the class. This protects the object's internal state from being change in unexpected or invalid ways.

In Python encapsulation is a convention rather a strict:

  • name - public, accessible from anywhere.
  • _name - protected, a signal to other developers "Don't touch this directly".
  • __name - private, Python renames it internally(name mangling) to discourage outside access.
class MpesaAccount:
    def __init__(self, owner_name, phone_number, balance=0):
        self.owner_name = owner_name
        self.phone_number = phone_number
        self.__balance = balance

    def deposit(self, amount):
        if amount <= 49:
            print("Deposit must be a minimum of KES 50.")
        else:
            self.__balance += amount
            print(f"You have successfully deposited {amount} ne acc bal is KES {self.__balance}")

    def withdraw(self, amount):  
        if amount > self.__balance:
            print("Insufficient Funds")
        else:
            self.__balance -= amount
            print(f"You have successfully withdrawn {amount} ne acc bal is KES {self.__balance}")

    def check_balance(self):
        return f"You account balance is KES {self.__balance}"
Enter fullscreen mode Exit fullscreen mode
emmanuel_mpesa = MpesaAccount("Emm", "0701000000")
emmanuel_mpesa.deposit(150)
Enter fullscreen mode Exit fullscreen mode

Output:

You have successfully deposited 150 ne acc bal is KES 150
Enter fullscreen mode Exit fullscreen mode

2. Inheritance

  • Inheritance allows a new class to(child class/subclass/derived class) reuse the attributes and methods of an existing class(parent class/super class/base class).
# Parent Class
class PublicService:
    def __init__(self, reg_number, route):
        self.reg_number = reg_number
        self.route = route   

    def describe(self):
        return f"Vehicle registaration number {self.reg_number} plies the {self.route} route."

    def collect_fare(self, amount):
        return f"KES {amount} fare collected on {self.reg_number}."


# Child class 1   
class Matatu(PublicService):
    def __init__(self, reg_number, route, sacco_name, capacity):
        super().__init__(reg_number, route)
        self.sacco_name = sacco_name
        self.capacity = capacity

    def describe(self):
        return f"Vehicle registaration number {self.reg_number}, of the sacco {self.sacco_name} plies the {self.route} route."
Enter fullscreen mode Exit fullscreen mode
kabuku = Matatu("KDQ 221Z", "Nairobi-Thika", "Super-Metro", 33)
kabuku.collect_fare(100)
Enter fullscreen mode Exit fullscreen mode

Output:

'KES 100 fare collected on KDQ 221Z.' 
Enter fullscreen mode Exit fullscreen mode
# Child Class 2
class BodaBoda(PublicService):
    def __init__(self, reg_number, route, rider_name):
        super().__init__(reg_number, route)
        self.rider_name = rider_name

    # def describe(self):
    #     return f"Boda Boda {self.reg_number}, rider {self.rider_name} is on the {self.route} route" 
Enter fullscreen mode Exit fullscreen mode
bodaboda = BodaBoda("KMZT 300Z", "CBD-Upper-Hill", "Emmanuel")
bodaboda.describe()
Enter fullscreen mode Exit fullscreen mode

Output:

'Vehicle registaration number KMZT 300Z plies the CBD-Upper-Hill route.'
Enter fullscreen mode Exit fullscreen mode

Multi-level inheritance

  • Multilevel inheritance in Python is an object-oriented programming feature where a derived (child) class inherits from another derived class, forming a sequential, multi-generational chain (e.g., Grandparent → Parent → Child). This structure allows the deepest child class to automatically access all attributes and methods across the entire ancestor hierarchy
  • Also inherited attributes and methods without super() function - another way of inheriting attributes and methods besides using super() function.
class company:

    title:str = "consultancy"

    def __init__(self, company_name:str):
        self.company_name:str = company_name

    def info(self):
        print(f"Company Name: {self.company_name}")
        return f"Company Name: {self.company_name}"


class manager(company):

    def __init__(self, manager_name:str, company_name:str):

        self.manager_name = manager_name
        self.company_name = company_name

    def info(self):
        response = company.info(self)
        print(f"The manager : {self.manager_name}, {response} ")
        return f"The manager : {self.manager_name}, {response} "

class employee(manager):

    def __init__(self,employee_name:str, manager_name:str, company_name:str):

        self.employee_name = employee_name
        self.manager_name = manager_name
        self.company_name = company_name

    def info(self):
        response = manager.info(self)
        print(f"The employee : {self.employee_name}, {response} ")
        return f"The employee : {self.employee_name}, {response} "

obj = employee("John Doe", "Alice Johnson", "Tech Solutions")
obj.info()
Enter fullscreen mode Exit fullscreen mode

Multiple Inheritance

  • Multiple inheritance is an object-oriented programming feature where a class inherits behaviors and attributes from more than one parent class
class company:

    title:str = "consultancy"

    def __init__(self, company_name:str):
        self.company_name:str = company_name

    def info(self):
        print(f"Company Name: {self.company_name}")
        return f"Company Name: {self.company_name}"


class employee(company):

    def __init__(self,employee_name:str, company_name:str):

        self.employee_name = employee_name
        self.company_name = company_name

    def info(self):
        response = company.info(self)
        print(f"The employee : {self.employee_name}, {response} ")


class contractor(company):

    def __init__(self, contractor_name:str, company_name:str):

        self.contractor_name = contractor_name
        self.company_name = company_name

    def info(self):
        response = company.info(self)
        print(f"The contractor : {self.contractor_name}, {response} ")


obj = employee("John Doe", "Tech Solutions")
obj.info()

obj2 = contractor("Jane Smith", "Tech Solutions")
obj2.info()
Enter fullscreen mode Exit fullscreen mode

3. Polymorphism

  • Polymorphism(Greek word for "many forms") means objects of different classes can respond to the same method call in their own way. You call the same method name on different objects, and each one behaves according to its own class's implementation.

Python supports polymorphism naturally through method overriding(child classses redefine a parent's method as seen in the Delivery() and VanDelivery()).

4. Abstraction

  • Abstraction means hiding complicated implementation details and exposing only the essential features that a user of the class actually needs. IN python, abstraction is commonly implemented using the abc module to define abstract base classes. (Classes that define required methods but cannot be instantiated directly, forcing the subclasses/child classes to provide the actual implentation)
from abc import ABC, abstractmethod

# Parent Class
class Shape(ABC):  # Inherits from ABC, it cannot be instantiated

    @abstractmethod
    def area(self):
        pass            # No implementation on purpose

    @abstractmethod
    def perimeter(self):
        pass          # No implementation on purpose 
Enter fullscreen mode Exit fullscreen mode
# Child Class
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        area = self.width * self.height

        return area

    def perimeter(self):
        perimeter = 2 * (self.height + self.width)
        return perimeter
Enter fullscreen mode Exit fullscreen mode
rect = Rectangle(10, 6)

rect.area()
Enter fullscreen mode Exit fullscreen mode

Output:

60
Enter fullscreen mode Exit fullscreen mode
rectange = Shape()
Enter fullscreen mode Exit fullscreen mode
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[69], line 1
----> 1 rectange = Shape()

TypeError: Can't instantiate abstract class Shape without an implementation for abstract methods 'area', 'perimeter'
Enter fullscreen mode Exit fullscreen mode

Conclusion

Object-Oriented Programming (OOP) in Python is a powerful paradigm that shifts the programming focus from functions to structured objects, making software more modular, scalable, and maintainable. Because "everything in Python is an object," OOP is not just an optional tool; it forms the core DNA of the language and its most popular libraries.

Top comments (0)