Tutorial

Object Oriented Programming in Python

6 min read

Object-oriented programming (OOP) is a popular programming paradigm that allows developers to organize code into reusable, modular components called objects. Python programming language supports OOP principles and enables developers to create powerful, scalable applications. OOP in Python is based on the concepts of classes and objects, which are used to encapsulate data and behavior into reusable, modular units.

In Python, OOP can be used for a wide range of applications, from building simple scripts to developing complex, enterprise-level software systems.

Class & Object in Python

In Python, a class is a blueprint or template for creating objects. It defines a set of attributes and methods that an object of that class will have. Attributes are variables that hold data, while methods are functions that define the behavior of the object. To create an object in Python, we need to first define a class.

Once the class is defined, we can create multiple objects based on that class. Each object created from the same class will have the same attributes and methods, but the data held by those attributes can differ.

Here is an example of a simple class in Python:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        
    def start_engine(self):
        print("The engine has started.")
        
    def stop_engine(self):
        print("The engine has stopped.")

In this example, the Car class has three attributes (make, model, and year) and two methods (start_engine and stop_engine). The __init__ method is a special method that initializes the attributes of the object when it is created.

To create an object from the Car class, we can do the following:

my_car = Car("Toyota", "Camry", 2021)

This creates an object called my_car based on the Car class. my_car has the attributes make="Toyota", model="Camry", and year=2021. We can call the methods of the object using dot notation:

my_car.start_engine() # Output: The engine has started.
my_car.stop_engine() # Output: The engine has stopped.

Each object created from the Car class will have its own set of attributes and methods, but they will all share the same blueprint defined by the Car class.

Inheritance in Python

Inheritance is an important concept in OOPs that allows us to create a new class by extending an existing class. The new class inherits the attributes and methods of the existing class, and can also add new attributes and methods or override existing ones.

In Python, we can create a subclass by specifying the superclass in the class definition. Here’s an example:

class Vehicle:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        
    def start_engine(self):
        print("The engine has started.")
        
    def stop_engine(self):
        print("The engine has stopped.")
        
class Car(Vehicle):
    def __init__(self, make, model, year, num_doors):
        super().__init__(make, model, year)
        self.num_doors = num_doors
        
    def honk_horn(self):
        print("Beep beep!")

In this example, Vehicle is the superclass, and Car is the subclass. The Car class extends the Vehicle class by adding a new attribute num_doors and a new method honk_horn. The super().__init__() method is used to call the constructor of the superclass and initialize the make, model, and year attributes of the Car object.

Now, we can create a Car object and call its methods:

my_car = Car("Toyota", "Camry", 2021, 4)
my_car.start_engine() # Output: The engine has started.
my_car.honk_horn() # Output: Beep beep!
print(my_car.num_doors) # Output: 4

In this example, my_car is a Car object that inherits the start_engine() method from the Vehicle superclass and adds the honk_horn() method and the num_doors attribute.

Encapsulation in Python

Encapsulation is a fundamental concept in object-oriented programming (OOP) that involves the bundling of data and methods that act on that data within a single unit, called a class.

The purpose of encapsulation is to protect the data from unauthorized access or modification from outside the class and to ensure that the data is accessed only through the methods defined in the class.

In Python, we can achieve encapsulation by defining class attributes and methods as private, using the double underscore __ prefix.

Private attributes and methods can only be accessed from within the class itself and are not directly accessible from outside the class.

Here’s an example:

class BankAccount:
    def __init__(self, account_number, balance):
        self.__account_number = account_number
        self.__balance = balance
        
    def deposit(self, amount):
        self.__balance += amount
        
    def withdraw(self, amount):
        if self.__balance >= amount:
            self.__balance -= amount
        else:
            print("Insufficient balance.")
            
    def get_balance(self):
        return self.__balance

In this example, the account_number and balance attributes are defined as private by using the double underscore prefix. The deposit(), withdraw(), and get_balance() methods are defined as public and can be accessed from outside the class.

Now, we can create a BankAccount object and call its methods:

my_account = BankAccount("1234567890", 1000)
my_account.deposit(500)
my_account.withdraw(200)
print(my_account.get_balance()) # Output: 1300

In this example, the account_number and balance attributes are not directly accessible from outside the class, but can only be accessed through the deposit(), withdraw(), and get_balance() methods. This ensures that the data is protected and can be accessed only through the methods defined in the class.

Polymorphism in Python

Polymorphism is a key concept in object-oriented programming (OOP) that allows objects of different classes to be used interchangeably, as long as they implement the same interface or have a common base class.

Polymorphism is often achieved through method overriding or method overloading.

In Python, you can achieve polymorphism through method overriding, where a subclass provides its own implementation of a method that is already defined in the superclass.

Here’s an example:

class Shape:
    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

Here, Shape is the base class, and Rectangle and Circle are subclasses. Each subclass provides its own implementation of the area() method, which calculates the area of the rectangle or circle based on its dimensions.

Now, you can create objects of Rectangle and Circle and call their area() methods:

my_rectangle = Rectangle(5, 10)
my_circle = Circle(7)
print(my_rectangle.area()) # Output: 50
print(my_circle.area()) # Output: 153.86

Here, the area() method is overridden in the Rectangle and Circle subclasses to provide their own implementation, which is different from the implementation in the Shape superclass.

However, both the Rectangle and Circle objects can be used interchangeably with the Shape object because they implement the same interface, which is the area() method.

Want to master Python programming, hire a Python tutor for yourself now!