Object-Oriented Programming (OOP) in Python

Object-Oriented Programming (OOP) is one of the most important paradigms in modern software development. Python, being a versatile and powerful programming language, fully supports OOP principles, allowing developers to design reusable, scalable, and efficient programs.

In this post, we will explore Object-Oriented Programming in Python in great detail — including concepts like classes, objects, inheritance, polymorphism, and encapsulation. We will go step-by-step through each concept, with explanations and examples that will help you understand how OOP works in Python.

What is Object-Oriented Programming?

Object-Oriented Programming is a programming paradigm that organizes software design around objects rather than functions or logic.

An object represents a real-world entity that has both attributes (data) and behaviors (methods).

The key idea behind OOP is to model your code in a way that mirrors how things exist and behave in the real world.

For example:

  • A Car can be modeled as a class.
  • The color, model, and speed can be its attributes.
  • The drive() and brake() actions can be its methods.

Advantages of OOP

Object-Oriented Programming offers several key advantages:

  1. Modularity – Code is organized into classes and objects, making it easier to maintain and understand.
  2. Reusability – Classes can be reused across multiple projects or modules.
  3. Extensibility – You can easily extend existing classes without modifying them.
  4. Scalability – OOP makes it easier to manage large applications.
  5. Encapsulation – Keeps data secure by restricting direct access.
  6. Polymorphism – Allows one interface to be used for different data types.

Classes and Objects

What is a Class?

A class is a blueprint for creating objects. It defines the properties (attributes) and behaviors (methods) that its objects will have.

For example:

class Car:
def __init__(self, brand, model):
    self.brand = brand
    self.model = model
def start_engine(self):
    print(f"{self.brand} {self.model}'s engine has started.")

Here,

  • Car is a class.
  • brand and model are attributes.
  • start_engine() is a method that defines the car’s behavior.

What is an Object?

An object is an instance of a class. It represents a specific entity that has the data and behavior defined by the class.

Example:

car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Civic")

car1.start_engine()
car2.start_engine()

Output:

Toyota Camry's engine has started.
Honda Civic's engine has started.

Each object (car1, car2) has its own data (brand and model) and can perform actions (methods).


The __init__ Method

The __init__ method is a special method in Python that is automatically called when an object is created. It is used to initialize the object’s attributes.

Example:

class Student:
def __init__(self, name, age):
    self.name = name
    self.age = age
student1 = Student("Alice", 20) print(student1.name) print(student1.age)

Output:

Alice
20

The self keyword refers to the instance of the class, allowing you to access or modify its attributes.


Instance Variables and Class Variables

In Python, you can have two types of variables in a class:

Instance Variables

These are variables that are unique to each instance (object) of a class.

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

Each Dog object has its own name attribute.

Class Variables

These are shared across all instances of a class.

class Dog:
species = "Canine"
def __init__(self, name):
    self.name = name
dog1 = Dog("Rex") dog2 = Dog("Buddy") print(dog1.species) print(dog2.species)

Output:

Canine
Canine

Methods in Classes

Methods are functions defined inside a class that describe the behaviors of an object.

Example:

class Calculator:
def add(self, a, b):
    return a + b
calc = Calculator() print(calc.add(10, 5))

Output:

15

You can define multiple methods inside a class to represent different behaviors.


The self Keyword

The self keyword represents the instance of the class and allows you to access its attributes and methods.

For example:

class Person:
def __init__(self, name):
    self.name = name
def greet(self):
    print(f"Hello, my name is {self.name}")

When you create an object, Python automatically passes the object itself as the first argument to the method.


Encapsulation

Encapsulation is one of the core principles of OOP. It means restricting access to certain details of an object and only exposing what is necessary.

It helps in:

  • Protecting the data from accidental modification.
  • Maintaining data integrity.

Example of Encapsulation

class BankAccount:
def __init__(self, balance):
    self.__balance = balance
def deposit(self, amount):
    if amount > 0:
        self.__balance += amount
    else:
        print("Invalid deposit amount")
def get_balance(self):
    return self.__balance
account = BankAccount(1000) account.deposit(500) print(account.get_balance())

Output:

1500

Here, __balance is a private variable. It cannot be accessed directly outside the class.

Attempting to access it will cause an error:

print(account.__balance)  # AttributeError

Encapsulation ensures that sensitive data remains safe.


Inheritance

Inheritance allows a class to inherit attributes and methods from another class.

This helps in reusing code and creating a logical hierarchy between classes.

Example:

class Animal:
def speak(self):
    print("Animal is speaking")
class Dog(Animal):
def bark(self):
    print("Dog is barking")
dog = Dog() dog.speak() dog.bark()

Output:

Animal is speaking
Dog is barking

Here, Dog inherits from Animal. This means the Dog class can use methods defined in the Animal class.


The super() Function

super() is used to call methods from the parent class.

Example:

class Person:
def __init__(self, name):
    self.name = name
class Employee(Person):
def __init__(self, name, salary):
    super().__init__(name)
    self.salary = salary

Here, the super() function initializes the parent class attributes, ensuring both parent and child attributes are set properly.


Types of Inheritance in Python

  1. Single Inheritance – One child class inherits from one parent class.
  2. Multiple Inheritance – One child class inherits from multiple parent classes.
  3. Multilevel Inheritance – A chain of inheritance (A → B → C).
  4. Hierarchical Inheritance – Multiple child classes inherit from one parent class.
  5. Hybrid Inheritance – A combination of the above types.

Example of Multiple Inheritance:

class Father:
def skills(self):
    print("Gardening, Programming")
class Mother:
def skills(self):
    print("Cooking, Painting")
class Child(Father, Mother):
def skills(self):
    super().skills()
    print("Dancing, Singing")
child = Child() child.skills()

Output:

Gardening, Programming
Dancing, Singing

Polymorphism

Polymorphism means many forms. In OOP, it allows objects of different classes to be treated as objects of a common base class.

It enables the same method to behave differently depending on the object that calls it.

Example of Polymorphism with Inheritance

class Bird:
def speak(self):
    print("Bird is making a sound")
class Parrot(Bird):
def speak(self):
    print("Parrot says hello")
class Crow(Bird):
def speak(self):
    print("Crow says caw")
for bird in [Parrot(), Crow()]:
bird.speak()

Output:

Parrot says hello
Crow says caw

Here, the same method name speak() behaves differently depending on the object type.


Polymorphism with Functions

You can also use polymorphism with functions that accept objects of different types.

Example:

class Cat:
def sound(self):
    return "Meow"
class Dog:
def sound(self):
    return "Bark"
def animal_sound(animal):
print(animal.sound())
cat = Cat() dog = Dog() animal_sound(cat) animal_sound(dog)

Output:

Meow
Bark

This demonstrates how polymorphism allows different classes to implement the same method with different behavior.


Abstraction

Abstraction means hiding unnecessary details and exposing only the essential features.

In Python, abstraction can be achieved using abstract classes and abstract methods from the abc module.

Example:

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
circle = Circle(5) print(circle.area())

Output:

78.5

Here,

  • Shape is an abstract class.
  • area() is an abstract method that must be implemented in any subclass.

Composition

Composition is another important concept in OOP where one class is composed of one or more objects of other classes.

It represents a “has-a” relationship.

Example:

class Engine:
def start(self):
    print("Engine started")
class Car:
def __init__(self):
    self.engine = Engine()  # Composition
def start(self):
    self.engine.start()
    print("Car is running")
car = Car() car.start()

Output:

Engine started
Car is running

This example shows that a car has an engine, demonstrating composition.


Magic Methods in OOP

Python classes have special methods called magic methods or dunder methods (double underscore).

Example:

  • __init__() – Initializes an object.
  • __str__() – Returns a string representation of an object.
  • __add__() – Defines behavior for the + operator.

Example of __str__ and __add__

class Number:
def __init__(self, value):
    self.value = value
def __add__(self, other):
    return self.value + other.value
def __str__(self):
    return f"Number({self.value})"
num1 = Number(10) num2 = Number(20) print(num1 + num2) print(num1)

Output:

30
Number(10)

Magic methods allow you to define how your objects behave with operators and built-in functions.


Real-Life Example of OOP in Python

Let’s create a simple simulation of a Library Management System using OOP principles.

class Book:
def __init__(self, title, author):
    self.title = title
    self.author = author
    self.is_available = True
def borrow(self):
    if self.is_available:
        self.is_available = False
        print(f"{self.title} has been borrowed.")
    else:
        print(f"{self.title} is not available.")
def return_book(self):
    self.is_available = True
    print(f"{self.title} has been returned.")
class Library:
def __init__(self):
    self.books = []
def add_book(self, book):
    self.books.append(book)
def show_books(self):
    for book in self.books:
        status = "Available" if book.is_available else "Borrowed"
        print(f"{book.title} by {book.author} - {status}")
book1 = Book("1984", "George Orwell") book2 = Book("Pride and Prejudice", "Jane Austen") library = Library() library.add_book(book1) library.add_book(book2) library.show_books() book1.borrow() library.show_books()

Output:

1984 by George Orwell - Available
Pride and Prejudice by Jane Austen - Available
1984 has been borrowed.
1984 by George Orwell - Borrowed
Pride and Prejudice by Jane Austen - Available

This example shows how OOP concepts like encapsulation, abstraction, and composition come together to create a functional program.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *