Complete Guide to Python OOP (Object-Oriented Programming)

In Python, Object-Oriented Programming (OOP) is a powerful way to organize and structure your code. It allows you to model real-world entities as objects and manage complex systems more efficiently.

In this guide, we’ll explore Python OOP fundamentals, including classes, objects, attributes, methods, the __init__ method, encapsulation, inheritance, polymorphism, and practical examples.


Classes and Objects

  • Class – a blueprint for creating objects.
  • Object – a specific instance of a class.
    
    class Car:
        pass
    
    my_car = Car()  # Creating an object from the Car class
    

    Attributes and Methods

  • Attributes are the properties of an object (e.g., color, model).
  • Methods are functions defined inside a class that describe the object’s behavior.

    
    class Car:
        def __init__(self, brand, model, year):
            self.brand = brand  # attribute
            self.model = model
            self.year = year
    
        def start_engine(self):  # method
            print(f"{self.brand} {self.model}'s engine has started!")
    
    my_car = Car("Toyota", "Corolla", 2020)
    my_car.start_engine()
    

    The __init__ Method

  • This special method is called automatically when an object is created.
  • It initializes the object’s attributes.

    Encapsulation

  • Encapsulation means restricting access to an object’s internal data.
  • In Python, private attributes or methods are prefixed with __.

    
    class Car:
        def __init__(self, brand, model):
            self.__brand = brand  # private attribute
            self.model = model
    
        def get_brand(self):
            return self.__brand
    
    my_car = Car("BMW", "X5")
    print(my_car.get_brand())
    

    Inheritance

    Inheritance allows one class to extend another, making it easier to reuse and organize code.

    
    class Vehicle:
        def __init__(self, brand):
            self.brand = brand
    
        def honk(self):
            print(f"{self.brand} is honking!")
    
    class Car(Vehicle):
        def start_engine(self):
            print(f"{self.brand}'s engine has started!")
    
    my_car = Car("Honda")
    my_car.honk()
    my_car.start_engine()
    

    Polymorphism

    Polymorphism allows the same method name to behave differently for different objects.

    
    class Dog:
        def speak(self):
            print("Woof!")
    
    class Cat:
        def speak(self):
            print("Meow!")
    
    animals = [Dog(), Cat()]
    for animal in animals:
        animal.speak()
    

    Code Examples

    Here is a more complete example combining classes, methods, inheritance, and polymorphism:

    
    class Employee:
        def __init__(self, name, salary):
            self.name = name
            self.salary = salary
    
        def work(self):
            print(f"{self.name} is working.")
    
    class Developer(Employee):
        def work(self):
            print(f"{self.name} is writing code.")
    
    class Manager(Employee):
        def work(self):
            print(f"{self.name} is managing the team.")
    
    employees = [Developer("Ali", 5000), Manager("Vali", 7000)]
    for e in employees:
        e.work()
    

    Mini Project: Banking System

    Task: Create a BankAccount class with attributes and methods for deposit, withdrawal, and balance display. Extend it with SavingsAccount and CurrentAccount subclasses.

    
    class BankAccount:
        def __init__(self, owner, balance=0):
            self.owner = owner
            self.balance = balance
    
        def deposit(self, amount):
            self.balance += amount
            print(f"${amount} deposited. Current balance: ${self.balance}")
    
        def withdraw(self, amount):
            if amount <= self.balance:
                self.balance -= amount
                print(f"${amount} withdrawn. Current balance: ${self.balance}")
            else:
                print("Insufficient balance!")
    
    class SavingsAccount(BankAccount):
        def add_interest(self, rate):
            self.balance += self.balance * rate / 100
            print(f"Interest added. Current balance: ${self.balance}")
    
    account = SavingsAccount("Ali", 1000)
    account.deposit(500)
    account.withdraw(200)
    account.add_interest(5)