OOPs Concepts in Python

Python Libraries

Object-Oriented Programming (OOP) is a way of organizing your code. It lets you create programs that are easy to understand and manage. In Python, OOP uses “objects” to represent real-world things or ideas. These objects combine data and the actions that can be performed on that data.

Using OOP helps you write code that is reusable and flexible. You can build complex systems by breaking them into smaller, manageable parts. This makes your programs easier to update and fix over time.

Here are the main concepts in Python OOP:

  • Classes
  • Objects
  • Inheritance
  • Encapsulation
  • Polymorphism
  • Abstraction

You can use these concepts to write better Python code.

1. Classes

A class is like a blueprint or a template. It defines a set of rules for creating objects. Think of a class as the design for a house. The design tells you what the house will have: how many rooms, where the windows are, and so on.

A class in Python defines:

  • Attributes: These are the data or properties that objects of this class will have. For a Car class, attributes might be color, make, or model.
  • Methods: These are the functions or actions that objects of this class can perform. For a Car class, methods might be start_engine(), drive(), or stop().

You create a class using the class keyword.

class Car:
    # This is an attribute common to all cars
    wheels = 4

    # This is a special method called a constructor.
    # It runs when you create a new Car object.
    def __init__(self, make, model, color):
        self.make = make      # Instance attribute
        self.model = model    # Instance attribute
        self.color = color    # Instance attribute

    # This is a method (an action the car can do)
    def drive(self):
        print(f"The {self.color} {self.make} {self.model} is driving.")

In this Car class, wheels is a class attribute. make, model, and color are instance attributes. The drive() method lets a car object perform an action.

2. Objects

An object is a real instance of a class. If a class is a blueprint for a house, an object is an actual house built from that blueprint. You can build many houses from one design, and each house is an object.

Each object has its own unique set of data based on the class’s attributes.

You create an object by calling the class name like a function.

# Create an object (an instance) of the Car class
my_car = Car("Toyota", "Camry", "blue")
your_car = Car("Honda", "Civic", "red")

# Access attributes of the objects
print(f"My car is a {my_car.color} {my_car.make} {my_car.model}.")
print(f"Your car has {your_car.wheels} wheels.")

# Call methods on the objects
my_car.drive()
your_car.drive()

This code outputs:

My car is a blue Toyota Camry.
Your car has 4 wheels.
The blue Toyota Camry is driving.
The red Honda Civic is driving.

my_car and your_car are two different objects. They use the same Car blueprint but have their own specific color, make, and model.

3. Inheritance

Inheritance lets you create a new class from an existing class. The new class, called the “child class” or “derived class,” gets all the attributes and methods of the original class, called the “parent class” or “base class.”

This helps you reuse code. You do not have to write the same code again. You can also add new features or change existing ones in the child class.

Think of a Vehicle class as a parent. A Car class and a Motorcycle class can inherit from Vehicle. Both cars and motorcycles are vehicles.

class Vehicle:
    def __init__(self, brand):
        self.brand = brand

    def start_engine(self):
        print(f"{self.brand} engine started.")

class Car(Vehicle):
    def __init__(self, brand, model):
        super().__init__(brand) # Call parent's constructor
        self.model = model

    def drive(self):
        print(f"The {self.brand} {self.model} is driving on four wheels.")

class Motorcycle(Vehicle):
    def __init__(self, brand, type_moto):
        super().__init__(brand)
        self.type_moto = type_moto

    def ride(self):
        print(f"The {self.brand} {self.type_moto} is riding on two wheels.")

# Create objects of child classes
my_car = Car("Ford", "Focus")
my_bike = Motorcycle("Harley-Davidson", "Cruiser")

# Child classes use methods from parent
my_car.start_engine()
my_bike.start_engine()

# Child classes use their own methods
my_car.drive()
my_bike.ride()

This code outputs:

Ford engine started.
Harley-Davidson engine started.
The Ford Focus is driving on four wheels.
The Harley-Davidson Cruiser is riding on two wheels.

The Car and Motorcycle classes inherit start_engine() from Vehicle. They also have their own specific methods (drive() and ride()).

4. Encapsulation

Encapsulation means bundling data (attributes) and methods that work on that data into a single unit (a class). It also means hiding the internal details of how a class works. You expose only what is necessary to the outside world.

Think of a remote control for a TV. You use buttons to change channels or volume. You do not need to know how the remote’s circuits work inside. Encapsulation works like this.

In Python, you can indicate that an attribute or method is “private” or “protected” by using underscores:

  • Public: Attributes/methods without underscores or with a single underscore. You can access them from anywhere.
  • Protected: Attributes/methods starting with a single underscore (e.g., _protected_attribute). This is a convention, meaning “don’t directly access this from outside the class unless you know what you are doing.” Python does not strictly prevent access.
  • Private: Attributes/methods starting with two underscores (e.g., __private_attribute). Python “mangles” these names to make them harder to access directly from outside the class.
class BankAccount:
    def __init__(self, initial_balance):
        self.__balance = initial_balance # Private attribute

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Deposited {amount}. New balance: {self.__balance}")
        else:
            print("Deposit amount must be positive.")

    def withdraw(self, amount):
        if amount > 0 and self.__balance >= amount:
            self.__balance -= amount
            print(f"Withdrew {amount}. New balance: {self.__balance}")
        else:
            print("Invalid withdrawal amount or insufficient funds.")

    def get_balance(self):
        return self.__balance

# Create a bank account object
my_account = BankAccount(1000)

# Interact with the account using public methods
my_account.deposit(200)
my_account.withdraw(500)
print(f"Current balance: {my_account.get_balance()}")

# Trying to access a "private" attribute directly (Python name mangles it)
# print(my_account.__balance) # This will cause an AttributeError

This code outputs:

Deposited 200. New balance: 1200
Withdrew 500. New balance: 700
Current balance: 700

You manage the __balance (private data) through deposit(), withdraw(), and get_balance() methods. This prevents direct, uncontrolled changes to the balance.

5. Polymorphism

Polymorphism means “many forms.” It lets you use the same function name for different types of objects. This means one function or method can act in many forms.

Think of a speak() method. A Dog object might speak() by barking, while a Cat object might speak() by meowing. The method name is the same, but the behavior is different based on the object type.

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

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

class Duck:
    def speak(self):
        print("Quack!")

# Function that takes an animal object and makes it speak
def make_animal_speak(animal):
    animal.speak()

# Create animal objects
my_dog = Dog()
my_cat = Cat()
my_duck = Duck()

# Call the same function with different animal objects
make_animal_speak(my_dog)
make_animal_speak(my_cat)
make_animal_speak(my_duck)

This code outputs:

Woof!
Meow!
Quack!

The make_animal_speak() function does not care what type of animal it receives. It just calls the speak() method, and the correct speak() method for that animal runs. This makes your code more flexible.

6. Abstraction

Abstraction means showing only the essential features of an object and hiding complex implementation details. It lets you focus on what an object does, not how it does it.

Imagine driving a car. You use the steering wheel, pedals, and gear stick. You do not need to know the complex mechanics of the engine or transmission. Abstraction hides these details.

In Python, you can achieve abstraction using abstract classes and methods. An abstract class cannot be created directly. It provides a blueprint that other classes must follow. The abc module (Abstract Base Classes) helps you do this.

from abc import ABC, abstractmethod

class Shape(ABC): # Shape is an abstract base class
    @abstractmethod
    def area(self):
        pass # Abstract method - must be implemented by child classes

    @abstractmethod
    def perimeter(self):
        pass # Abstract method

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

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

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

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

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

    def perimeter(self):
        return 4 * self.side

# Create objects
my_circle = Circle(5)
my_square = Square(4)

# Calculate and print
print(f"Circle area: {my_circle.area()}")
print(f"Square perimeter: {my_square.perimeter()}")

# Trying to create an abstract class directly will raise an error
# abstract_shape = Shape() # This would give a TypeError

This code outputs:

Circle area: 78.5
Square perimeter: 16

The Shape class defines area() and perimeter() as abstract methods. Any class inheriting from Shape must implement these methods. You focus on the idea of a Shape having an area and perimeter, not the exact calculation method.

Conclusion

OOP concepts in Python help you write organized, reusable, and flexible code. Understanding classes and objects lets you model real-world problems in your programs. Inheritance helps you reuse code. Encapsulation protects your data. Polymorphism makes your code adaptable. Abstraction simplifies complex systems.

Avatar photo
Great Learning Editorial Team
The Great Learning Editorial Staff includes a dynamic team of subject matter experts, instructors, and education professionals who combine their deep industry knowledge with innovative teaching methods. Their mission is to provide learners with the skills and insights needed to excel in their careers, whether through upskilling, reskilling, or transitioning into new fields.

Academy Pro Subscription

Grab 50% off
on Top Courses - Free Trial Available

×
Scroll to Top