OOP in Python

OOP IN PYTHON


Introduction

Until now, We have thought of programs as a step by step list of instructions or algorithms. This works if we are trying to simulate only a process that we can observe in real life like preparing a cup of tea, calculating total marks of a student, Finding area of a triangle and such. This is called functional or structural programming. 
Now, Lets imagine a different scenario, What if we need to simulate a water bottle, a table, a human, a car or anything from real world that isn't a process but rather an entity. How do we create a water bottle ? What data or value should a water bottle have? Our conventional programming fails here. But if we dumb down a water bottle. we can extract some key data from it and categorize the data into 2 sections:

Data members(attributes):

  1. Color
  2. Material
  3. Shape
  4. Cost
  5. Capacity
  6. Company
  7. Brand

Ways to Interact with said data members(methods):

  1. fill up
  2. empty out
  3. break
  4. buy
  5. sell

The data extracted from real entities are called as attributes. The functions that are used to interact with those data are called as methods. The process of bundling them together is Encapsulation. The final data structure we get after encapsulating them is called a Class. We copy a class and then assign actual data(like actual color, actual brand...) inside the copy, that copy is called an Object. We can mix and match different classes to get more flexibility and reusable code to get more classes, this process is called Inheritance.  While doing so, we create a layer of separation/privacy between the different classes, it is called Abstraction. Many classes can have same methods but do different things in their core, This is called Polymorphism. These are the 4 pillars of OOP.

 
Object-Oriented Programming (OOP) is a programming paradigm centered around the concept of "objects." Objects are instances of classes that encapsulate data (attributes) and behavior (methods). OOP allows for a structured and modular approach to programming, making it easier to manage and scale complex software systems.

Class in Python

A class in Python serves as a blueprint for creating objects. It defines the attributes and methods that the objects created from the class will have. Classes help organize code and promote code reuse by allowing the creation of multiple objects with similar properties and behavior.

Example:

class Car:
    #data can be inside or outside of methods
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    #this is a method that interacts with the hypothetical engine
    def start_engine(self):
        return f"The {self.make} {self.model} engine has started."

# Creating an object of the Car class
my_car = Car("Toyota", "Corolla", 2020)
print(my_car.start_engine())

This example defines a Car class with attributes like make, model, and year, and a method start_engine. An object my_car is created using the Car class, and the start_engine method is called.

Objects in Python

Objects are instances of classes. They represent specific instances of the blueprint provided by the class. Each object can have different attribute values but share the same methods defined by the class.

Example:

# Creating another object of the Car class
another_car = Car("Honda", "Civic", 2018)
print(another_car.start_engine())

In this example, another_car is another object of the Car class with different attribute values, but it shares the same method start_engine.

Polymorphism in Python

Polymorphism allows objects of different classes to be treated as objects of a common superclass. It is a key concept in OOP that enables methods to be used on objects of different types, often through method overriding and method overloading.

Example:

class Animal:
    def sound(self):
        pass

class Dog(Animal):
    def sound(self):
        return "Woof!"

class Cat(Animal):
    def sound(self):
        return "Meow!"

def make_sound(animal):
    print(animal.sound())

dog = Dog()
cat = Cat()

make_sound(dog)  # Outputs: Woof!
make_sound(cat)  # Outputs: Meow!

This example demonstrates polymorphism through method overriding, where the sound method is defined differently in the Dog and Cat classes, but both can be used with the make_sound function.

Encapsulation in Python

Encapsulation is the practice of bundling the data (attributes) and the methods (functions) that operate on the data into a single unit or class. It restricts direct access to some of the object's components, which is a means of preventing unintended interference and misuse of the data.

Example:

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

    def deposit(self, amount):
        self.__balance += amount

    def withdraw(self, amount):
        if amount <= self.__balance:
            self.__balance -= amount
            return amount
        else:
            return "Insufficient funds"

    def get_balance(self):
        return self.__balance

account = BankAccount(1000)
account.deposit(500)
print(account.get_balance())  # Outputs: 1500

In this example, the __balance attribute is private, meaning it cannot be accessed directly from outside the class. Instead, methods like deposit, withdraw, and get_balance provide controlled access to the balance.

Inheritance in Python

Inheritance is a mechanism in OOP that allows a new class (derived class) to inherit attributes and methods from an existing class (base class). It promotes code reuse and establishes a relationship between classes.

Example:

class Vehicle:
    def __init__(self, make, model):
        self.make = make
        self.model = model

    def start_engine(self):
        return "Engine started"

class Car(Vehicle):
    def start_engine(self):
        return f"The {self.make} {self.model} engine is roaring!"

my_car = Car("Ford", "Mustang")
print(my_car.start_engine())

In this example, the Car class inherits from the Vehicle class but overrides the start_engine method to provide a more specific implementation.

Data Abstraction in Python

Data abstraction is the concept of exposing only the necessary information to the outside world while hiding the implementation details. This is typically achieved using abstract classes and interfaces, but in Python, it can also be done using abstract base classes (ABCs) from the abc module.

Example:

from abc import ABC, abstractmethod

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

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

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

rect = Rectangle(4, 5)
print(rect.area())  # Outputs: 20

In this example, the Shape class is an abstract base class with an abstract method area. The Rectangle class inherits from Shape and provides an implementation for the area method.

Conclusion

Object-Oriented Programming in Python is a powerful paradigm that helps in structuring and organizing code. Concepts like classes, objects, polymorphism, encapsulation, inheritance, and data abstraction are fundamental to OOP and are essential for building robust and maintainable software systems. Understanding and applying these concepts effectively will significantly enhance your ability to write clean, efficient, and reusable code.