Object oriented programming in Python

 


Object-Oriented Programming (OOP) in Python is a programming paradigm based on the concept of objects, which bundle data (attributes) and behavior (methods). Python supports OOP fully and makes it simple and flexible.


🧩 Core Concepts of OOP

1. Class

A class is a blueprint for creating objects.

class Car:
    pass

2. Object

An object is an instance of a class.

my_car = Car()

3. Attributes

Variables that belong to a class or object.

class Car:
    def __init__(self, brand, color):
        self.brand = brand
        self.color = color

4. Methods

Functions inside a class that describe behaviors.

class Car:
    def start_engine(self):
        print("Engine started!")

5. The __init__ Constructor

Called automatically when an object is created.

class Car:
    def __init__(self, brand, color):
        self.brand = brand
        self.color = color

6. Encapsulation

Restricting direct access to data. Python uses naming conventions:

  • _protected_attribute
  • __private_attribute
class Person:
    def __init__(self, name):
        self.__name = name  # private

    def get_name(self):
        return self.__name

7. Inheritance

A class can inherit properties and methods from another class.

class Animal:
    def sound(self):
        print("Some sound")

class Dog(Animal):
    def sound(self):
        print("Bark!")

8. Polymorphism

Same method name, different behaviors.

for animal in [Dog(), Animal()]:
    animal.sound()   # Different outputs

9. Abstraction

Hiding complex details using abstract classes (via abc module).

from abc import ABC, abstractmethod

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

✔️ Complete Example

class Car:
    def __init__(self, brand, color):
        self.brand = brand
        self.color = color

    def drive(self):
        print(f"The {self.color} {self.brand} is driving.")

class ElectricCar(Car):
    def __init__(self, brand, color, battery_capacity):
        super().__init__(brand, color)
        self.battery_capacity = battery_capacity

    def drive(self):
        print(f"The electric {self.color} {self.brand} is silently driving.")

tesla = ElectricCar("Tesla", "red", 100)
tesla.drive()

🎯 Why Use OOP?

  • Code reusability
  • Modularity
  • Easier maintenance
  • Real-world modeling

Great — let’s go deeper into Object-Oriented Programming in Python with more advanced concepts, examples, diagrams, and best practices.


🔥 1. Class vs Instance Attributes

Instance Attributes

Unique to each object.

class Student:
    def __init__(self, name):
        self.name = name  # instance attribute

Class Attributes

Shared across all instances.

class Student:
    school = "Greenwood High"  # class attribute

    def __init__(self, name):
        self.name = name
s1 = Student("Alice")
s2 = Student("Bob")

print(s1.school)  # Greenwood High
print(s2.school)  # Greenwood High

🔥 2. Method Types

Instance Method

Most common — works on object attributes.

def study(self):
    print(self.name, "is studying")

Class Method

Uses @classmethod and cls.

class Person:
    count = 0

    def __init__(self):
        Person.count += 1

    @classmethod
    def how_many(cls):
        return cls.count

Static Method

No self or cls — utility functions.

class Math:
    @staticmethod
    def add(a, b):
        return a + b

🔥 3. Inheritance (Single, Multi-level, Multiple)

Single Inheritance

class A:
    pass

class B(A):
    pass

Multi-level Inheritance

class A:
    pass

class B(A):
    pass

class C(B):
    pass

Multiple Inheritance

class A:
    pass
class B:
    pass
class C(A, B):
    pass

Python solves method conflicts using MRO (Method Resolution Order).


🔥 4. Super() and Method Overriding

Using super()

class Parent:
    def show(self):
        print("Parent")

class Child(Parent):
    def show(self):
        super().show()   # call Parent show()
        print("Child")

🔥 5. Polymorphism with Duck Typing

Python doesn’t require explicit interfaces.

class Cat:
    def sound(self):
        print("Meow")

class Dog:
    def sound(self):
        print("Bark")

def make_sound(animal):
    animal.sound()

make_sound(Dog())
make_sound(Cat())

🔥 6. Operator Overloading (Dunder Methods)

Python allows custom behavior for built-in operators:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

v1 = Vector(1, 3)
v2 = Vector(4, 2)
v3 = v1 + v2
print(v3.x, v3.y)

🔥 7. Properties (Getters and Setters)

Pythonic way to control attribute access.

class Person:
    def __init__(self, age):
        self._age = age

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if value < 0:
            raise ValueError("Age cannot be negative")
        self._age = value

🔥 8. Abstract Classes

Used to enforce methods in subclasses.

from abc import ABC, abstractmethod

class Shape(ABC):

    @abstractmethod
    def area(self):
        pass

🔥 9. Composition (HAS-A relationship)

class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()   # Car HAS-A Engine

    def start(self):
        self.engine.start()

🔥 10. Best Practices for OOP in Python

Principle Description
SRP Single Responsibility Principle
OCP Open/Closed Principle
LSP Liskov Substitution Principle
ISP Interface Segregation
DIP Dependency Inversion
Use properties Avoid exposing raw attributes
Prefer composition over inheritance More flexible

🔥 11. Putting It All Together (Mini Project Example)

from abc import ABC, abstractmethod

class Account(ABC):
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    @abstractmethod
    def withdraw(self, amount):
        pass

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

class SavingsAccount(Account):
    def withdraw(self, amount):
        if amount > self.balance:
            print("Insufficient funds")
        else:
            self.balance -= amount

class Bank:
    def __init__(self):
        self.accounts = []

    def add_account(self, acc):
        self.accounts.append(acc)

bank = Bank()
acc1 = SavingsAccount("Alice", 500)
bank.add_account(acc1)

acc1.deposit(200)
acc1.withdraw(100)
print(acc1.balance)

If you want, I can continue with:

✅ Real-world OOP project
✅ UML diagrams
✅ OOP interview questions
✅ Exercises with solutions
✅ Advanced topics (mixins, metaclasses, decorators in OOP)

Just tell me “More” or specify what you want!


Post a Comment

0 Comments