Python OOPs Concepts with simple examples

Object Oriented Programming Concepts

Object Oriented Programming (OOP)

Object-Oriented Programming (OOP) is a programming paradigm that uses objects and their interactions to design applications and computer programs. Python, like many other programming languages, supports OOP and provides several features to implement it. In this article, we will cover the basics of OOP concepts in Python and provide some simple examples to illustrate them.

Class & Object

The first OOP concept we will discuss is classes. A class is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods). For example, let's consider a class called "Person" with a name and age as attributes, and a method called "greet()" that returns a greeting message.

The __init__ a method is a unique method that is called when an object is created from a class and it is used to initialize the attributes of the object. The self parameter is a reference to the current instance of the class and is used to access the attributes and methods of the object.

Inheritance

The next OOP concept is inheritance. Inheritance is a mechanism that allows a new class to be derived from an existing class. The derived class inherits the attributes and methods of the base class and can also have additional attributes and methods of its own. For example, let's consider a class called "Student" that inherits from the "Person" class.

The super() function is used to call the methods of the base class and super().__init__(name, age) is used to call the __init__ method of the base class and initialize the attributes inherited from the base class.

Polymorphism

The next OOP concept is polymorphism. Polymorphism is the ability of an object to take on many forms. In Python, polymorphism is achieved through method overriding and method overloading. Method overriding occurs when a derived class has a method with the same name as a method in the base class and the derived class method overrides the base class method. Method overloading is not supported in Python but can be achieved using default arguments or variable-length arguments.

Here are some examples of polymorphism in Python:

  • Method Overriding:

In this example, the Shape class has a area method that has a pass statement and is overridden by the Rectangle and Circle classes to provide their respective area calculations. And, when we iterate through the list of shapes and call the area method, it will output the respective area of rectangle and circle.

  • Method overloading is not supported in Python but can be achieved using default arguments or variable-length arguments.

In this example, the Calculator class has an add the method that takes two required arguments and any number of additional arguments. This allows the method to handle different numbers of arguments, providing the functionality of method overloading.

As you can see, polymorphism in Python allows objects to take on many forms, making the code more flexible and reusable. Method overriding allows derived classes to provide their implementation of a method from the base class, and method overloading can be achieved using default arguments or variable-length arguments.

Encapsulation

Last but not least OOP concept is encapsulation. Encapsulation is the practice of keeping an object's internal state and behavior is hidden from the outside world and exposing only a public interface for interacting with the object. In Python, encapsulation is achieved by using the _ and __ prefix to indicate the visibility of attributes and methods. Attributes and methods with a single _ prefix.

Here are some examples of encapsulation in Python:

  1. Using a single underscore prefix to indicate private attribute:
class BankAccount:
    def __init__(self, balance):
        self._balance = balance  # private attribute

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

    def withdraw(self, amount):
        if self._balance - amount >= 0:
            self._balance -= amount
        else:
            print("Insufficient funds.")

acct = BankAccount(1000)
print(acct._balance)  # This will work but not recommended
# Output: 1000

In this example, the BankAccount the the class has a private attribute _balance which can be accessed and modified only within the class. However, it can still be accessed from outside the class but it is not recommended and is considered a bad practice.

  1. Using double underscore prefixes to indicate private attributes and name mangling:
Copy codeclass BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # private attribute

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

    def withdraw(self, amount):
        if self.__balance - amount >= 0:
            self.__balance -= amount
        else:
            print("Insufficient funds.")

acct = BankAccount(1000)
print(acct.__balance)  # This will throw an error
# Output: AttributeError: 'BankAccount' object has no attribute '__balance'

In this example, the BankAccount class uses the double underscore prefix to indicate a private attribute __balance. This causes a process called name mangling, where the attribute name is changed to _ClassName__attribute in this case _BankAccount__balance so it can't be accessed directly from outside the class.

Encapsulation in Python allows the internal state and behavior of an object to be hidden from the outside world and exposes only a public interface for interacting with the object. This improves the security and maintainability of the code and makes it less prone to errors.

Abstraction

Abstraction is a concept that is closely related to encapsulation, and it is one of the fundamental principles of object-oriented programming. It refers to the process of hiding the implementation details of an object and exposing only the necessary information required to interact with it.

In Python, abstraction can be achieved through the use of interfaces and abstract classes. An interface is a collection of method signatures that define a contract that classes must follow. An abstract class is a class that contains one or more abstract methods, which are methods that do not have a implementation.

Here are some examples of abstraction in Python:

  1. Using Interfaces:
Copy codefrom 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

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

In this example, the Shape interface defines the area method, which must be implemented by any class that inherits from it. The Rectangle and Circle classes implement the area method and provide their respective area calculations.

  1. Using Abstract Classes:
Copy codefrom 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

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return 3.14 * self.radius ** 2

The key difference between using an interface and an abstract class is that a class can implement multiple interfaces but can only inherit from one abstract class.

Abstraction in Python allows developers to hide the implementation details of an object and expose only the necessary information required to interact with it. This improves the maintainability and readability of the code and makes it less prone to errors. By defining an interface or an abstract class, developers can specify the contract that classes must follow, ensuring that the objects behave as expected.

Summary

Object-Oriented Programming (OOP) is a powerful programming paradigm that helps developers design and build robust and maintainable software. Python, like many other programming languages, supports OOP and provides several features to implement it. Through this article, we have covered the basics of OOP concepts in Python, such as classes, inheritance, polymorphism, encapsulation, and abstraction, and provided examples to illustrate them. Understanding and utilizing these concepts can help developers write cleaner, more organized, and more efficient code. In addition, OOP concepts make the code more reusable, maintainable, and understandable. These concepts are the building blocks of Object-oriented programming and mastering them will help you to create more sophisticated, robust, and scalable applications.

Did you find this article valuable?

Support Nimmala Vasanth by becoming a sponsor. Any amount is appreciated!