Thanks to visit codestin.com
Credit goes to flexiple.com

Flexiple Logo
  1. Home
  2. Blogs
  3. Python
  4. Python OOPs Concepts

Python OOPs Concepts

Author image

Harsh Pandey

Software Developer

Published onĀ Tue Mar 12 2024

Python's Object-Oriented Programming (OOP) is a paradigm that uses objects and classes to organize code. Key concepts include classes (blueprints for objects), objects (instances of classes), inheritance (a way to form new classes using classes that have already been defined), encapsulation (hiding the internal state of an object), and polymorphism (the ability to use a shared interface for multiple forms). These concepts streamline and enhance code reusability, scalability, and efficiency.

Python Class

A Python class is a blueprint for creating objects, encapsulating data and functions that operate on that data. It employs the class keyword, followed by the class name and a colon. Inside, variables and methods are defined to establish the properties and behaviors of the objects created from the class.

Classes support modularity and code reuse. They lay the foundation for inheritance, allowing one class to inherit attributes and methods from another, promoting code efficiency and hierarchy.

Consider this simple example.

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

    def bark(self):
        return f"{self.name} says woof!"

# Create an instance of Dog
my_dog = Dog("Buddy", 4)

print(my_dog.bark())

Output: Buddy says woof!

In this example, Dog is a class defining attributes name and age, and a method bark(). my_dog is an object of the Dog class, demonstrating how a class serves as a template for creating objects with specific attributes and behaviors.

Python Objects

Python objects are instances of classes, embodying the principles of encapsulation and abstraction. These objects hold data, represented by attributes, and behavior, represented by methods. In Python, everything is an object, from simple data types to complex functions and modules, reflecting the language's adherence to object-oriented programming principles.

For instance, creating a class Car with a method to display its speed, and then instantiating an object of Car, can be done as follows.

class Car:
    def __init__(self, speed):
        self.speed = speed
    
    def display_speed(self):
        print(f"The car is moving at {self.speed} km/h.")

# Creating an object of the Car class
my_car = Car(150)
my_car.display_speed()

Output: The car is moving at 150 km/h.

This example showcases the instantiation of an object (my_car) from the class Car, encapsulating the car's speed as an attribute and providing a method to display it, illustrating Python's object-oriented nature.

Creating An Object

Creating an object in Python involves defining a class and then instantiating it. A class is a blueprint for the object, detailing its structure and behaviours. To create an object, you simply call the class as if it were a function. This process generates an instance of the class, which embodies all its characteristics.

Here is an example of creating a simple class named Car and an object of that class.

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

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

print(f"My car is a {my_car.make} {my_car.model}.")

Output: My car is a Toyota Corolla.

In this example, Car is the class with an __init__ method that initializes the object's attributes. my_car is an instance of the Car class, created with the make "Toyota" and the model "Corolla". The print statement then accesses these attributes, demonstrating how an object encapsulates data and behaviors defined by its class.

The Python Self

The Python self represents the instance of the object itself. This keyword is explicitly used in method definitions within a class to access attributes and methods of the class in which it is used. It helps differentiate between instance attributes and method calls from static attributes or methods belonging to the class.

self is not a reserved keyword in Python but a strong convention. During the invocation of a method, Python passes the object to the method as the first argument automatically. This argument refers to the object itself, enabling access to its attributes and methods.

For example, consider a simple class definition for a Car that has an attribute color and a method to display that color.

class Car:
    def __init__(self, color):
        self.color = color
    
    def show_color(self):
        print(f"The color of the car is {self.color}.")

my_car = Car("red")
my_car.show_color()

Output: The color of the car is red.

In this code, self.color assigns the value passed during object creation to the instance attribute color. The method show_color uses self to access the instance attribute color and prints its value.

The Python __init__ Method

The Python __init__ method is a fundamental aspect of Object-Oriented Programming (OOP) in Python. It acts as a constructor for a class, initializing new objects with default or specified values. This method is automatically called when a new class instance is created, allowing for the object's initial state to be configured.

In essence, the __init__ method lays the groundwork for attributes of new objects, ensuring each instance starts with the same baseline or customized states as defined within. This is crucial for encapsulation, one of the core principles of OOP, as it keeps object data safe and accessible only through the class's methods.

Here's a simple example to illustrate the __init__ method in action.

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

# Create a new Car object
my_car = Car('Toyota', 'Corolla')

# Print the object's attributes
print(f'My car is a {my_car.make} {my_car.model}.')

Output: My car is a Toyota Corolla.

This code snippet demonstrates how the init method initializes the make and model attributes of the Car class. Each Car object can now start with its own make and model, showcasing the method's role in defining an object's initial state.

Creating A class And Object With Class And Instance Attributes

Creating a class and object in Python involves defining a class with its attributes and methods, then instantiating objects from that class. Class attributes are shared across all instances, while instance attributes are specific to each object.

To define a class in Python, use the class keyword followed by the class name and a colon. Inside the class, you can define attributes and methods. Class attributes are defined directly beneath the class declaration, and instance attributes are typically set in a method called __init__, the class's constructor.

Here's a simple example.

class Car:
    # Class attribute
    wheels = 4

    # The __init__ method initializes an instance of the class.
    def __init__(self, make, model):
        # Instance attributes
        self.make = make
        self.model = model

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

# Accessing class and instance attributes
print(f"My car is a {my_car.make} {my_car.model} with {Car.wheels} wheels.")

Output: My car is a Toyota Corolla with 4 wheels.

This example demonstrates how to create a class with both class and instance attributes in Python, and how to instantiate an object of that class. The class attribute wheels is shared among all instances of the Car class, while make and model are instance attributes unique to each Car object.

Creating Classes And Objects With Methods

Creating classes and objects with methods is foundational to Python's Object-Oriented Programming (OOP). In Python, a class is a blueprint for creating objects, and methods are functions defined within a class that operate on the objects created from the class. This structure allows for the encapsulation of data and functions that manipulate this data within one cohesive unit.

To define a class in Python, use the class keyword, the class name and a colon. Inside the class, methods are defined as functions, with the first parameter traditionally named self to refer to the object's instance.

Here is a simple example.

class Dog:
    # Initializer / Instance Attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    # method to describe the dog
    def describe(self):
        return f"{self.name} is {self.age} years old."

# Create instances of the Dog class
dog1 = Dog("Buddy", 4)
dog2 = Dog("Lucy", 2)

# Output
print(dog1.describe())  # Buddy is 4 years old.
print(dog2.describe())  # Lucy is 2 years old.

Python Inheritance

Python Inheritance allows one class to derive or inherit the properties from another class. This mechanism enables code reusability by allowing a new class, known as the child class, to adopt attributes and methods of an existing class, called the parent class. Inheritance facilitates hierarchy and reduces redundancy.

For instance, consider a parent class Vehicle and a child class Car that inherits from Vehicle.

class Vehicle:
    def __init__(self, name, speed):
        self.name = name
        self.speed = speed

    def display_info(self):
        return f"Vehicle Name: {self.name}, Speed: {self.speed}km/h"

class Car(Vehicle):
    def __init__(self, name, speed, mileage):
        super().__init__(name, speed)
        self.mileage = mileage

    def display_car_info(self):
        return f"{super().display_info()}, Mileage: {self.mileage}mpg"

# Creating an object of Car
my_car = Car("Honda Civic", 220, 30)

# Output
print(my_car.display_car_info())

Output: Vehicle Name: Honda Civic, Speed: 220km/h, Mileage: 30mpg

In this example, Car inherits from Vehicle, enabling Car to use the display_info method from Vehicle and add additional details specific to Car. This demonstrates the power of inheritance in organizing and reusing code efficiently.

Python Polymorphism

Python Polymorphism refers to the ability of different objects to respond, in their own way, to the same method call. In Python, polymorphism allows us to define methods in the child class with the same name as defined in their parent class. This concept is integral to OOPs, enabling flexibility and multiple forms of behaviors.

For instance, consider two classes, Dog and Cat, each with a method speak(). Despite sharing the same method name, they can produce different outputs based on their respective class implementations.

class Dog:
    def speak(self):
        return "Woof!"

class Cat:
    def speak(self):
        return "Meow!"

def animal_sound(animal):
    print(animal.speak())

# Creating objects
dog = Dog()
cat = Cat()

# Polymorphism in action
animal_sound(dog)  # Output: Woof!
animal_sound(cat)  # Output: Meow!

This example demonstrates polymorphism where animal_sound function calls the speak method on an animal object, and each animal object (Dog or Cat) responds in its unique way to the speak method call.

Python Encapsulation

Python encapsulation is a fundamental concept in Object-Oriented Programming (OOP) that revolves around the bundling of data attributes and methods within a single class. This principle restricts direct access to some of the object's components, which is crucial for safeguarding the internal state of the object and ensuring data integrity. Encapsulation allows the creation of a controlled interface for interaction with the object, enabling the hiding of specific details and exposing only what is necessary.

In Python, encapsulation is implemented using private and protected member variables and methods. A single underscore (_) prefix makes an attribute or method protected, while a double underscore (__) prefix makes it private. However, it's important to note that this does not enforce strict access control but rather serves as a convention to indicate that a member is intended for internal use within the class.

Here is a simple example of encapsulation in Python.

class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.__balance = balance  # private attribute

    def deposit(self, amount):
        self.__balance += amount
        print(f"Added {amount} to the balance")

    def withdraw(self, amount):
        if amount > self.__balance:
            print("Insufficient balance")
        else:
            self.__balance -= amount
            print(f"Withdrew {amount} from the balance")

    def get_balance(self):
        return f"Current balance: {self.__balance}"

# Creating an Account object
acc = Account("John", 1000)
acc.deposit(500)
acc.withdraw(200)
print(acc.get_balance())

Output:

  • Added 500 to the balance
  • Withdrew 200 from the balance
  • Current balance: 1300

In this example, the __balance attribute of the Account class is private, meaning it cannot be accessed directly from outside the class. The deposit, withdraw, and get_balance methods provide a controlled way to modify and access the account's balance, showcasing encapsulation by hiding the internal implementation and exposing only the required functionalities.

Data Abstraction

Data abstraction in Python OOPs concepts refers to the process of hiding the complex implementation details from the user and only exposing the essential features of an object. This principle is implemented through the use of abstract classes and methods, which are declared but not defined. Abstract classes serve as blueprints for other classes, dictating the structure without providing specific implementations.

For example, consider an abstract class Shape with an abstract method area(). This method is defined in the derived classes, such as Circle and Square, which implement the area() method to calculate the area specific to their shape.

from abc import ABC, abstractmethod

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

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

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

class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side * self.side

# Creating objects
circle = Circle(5)
square = Square(4)

# Printing areas
print(circle.area())  # Output: 78.5
print(square.area())  # Output: 16

In this example, the Shape class abstracts the concept of a shape by defining a structure that all specific shapes (like Circle and Square) must follow. The user interacts with instances of Circle and Square without needing to know the details of how the area is calculated, showcasing data abstraction.

Related Blogs

Browse Flexiple's talent pool

Explore our network of top tech talent. Find the perfect match for your dream team.