Object-Oriented Programming (OOP) is one of the most powerful ways to structure Python programs. Instead of writing long scripts, OOP lets you build reusable components—called objects—that combine data and behavior together. This lesson takes you from the very basics of classes and objects all the way to advanced concepts like dataclasses, abstract classes, polymorphism, MRO, and common design patterns.
1) What Is OOP?
OOP is a programming style where you model real-world concepts as objects.
For example, a Car object may have:
- Attributes →
color,model,speed - Methods →
start(),accelerate(),stop()
You write the blueprint once — that's the class. Then you create many objects from it.
2) Creating Your First Class & Object
class Car:
def __init__(self, model, color):
self.model = model # instance attribute
self.color = color
def drive(self):
print(f"{self.model} is driving...")
# Creating objects
c1 = Car("Toyota Corolla", "White")
c2 = Car("Honda Civic", "Black")
c1.drive()
c2.drive()
What is happening?
class Car:→ defines the blueprint__init__→ constructor (runs when object is created)self→ refers to the current object
3) Instance Variables vs Class Variables
class Student:
school = "Geeksters Academy" # class variable (shared)
def __init__(self, name, score):
self.name = name # instance variable
self.score = score
s1 = Student("Ali", 90)
s2 = Student("Ammar", 85)
print(s1.school, s2.school)
- Instance variables = each object has its own
- Class variables = shared by all objects
4) Instance Methods, Class Methods & Static Methods
a) Instance Method (most common)
class Person:
def greet(self):
print("Hello from instance method")
b) Class Method
Used when you want a method that works at class level.
class Person:
count = 0
@classmethod
def get_count(cls):
return cls.count
c) Static Method
Used for utility/helper functions.
class MathTools:
@staticmethod
def add(a, b):
return a + b
5) String Representation — __str__ & __repr__
class User:
def __init__(self, name):
self.name = name
def __str__(self):
return f"User(name={self.name})"
6) Encapsulation — Public, Protected, Private
class BankAccount:
def __init__(self, balance):
self._balance = balance # protected
self.__pin = "1234" # private
def deposit(self, amount):
self._balance += amount
def get_balance(self):
return self._balance
public→ free to access_protected→ internal use__private→ name-mangled
7) Inheritance — Reusing Behavior
class Animal:
def speak(self):
print("Some sound")
class Dog(Animal):
def speak(self):
print("Woof!") # overriding
8) Polymorphism (Many Forms)
class Cat:
def speak(self):
print("Meow")
class Dog:
def speak(self):
print("Woof")
for pet in (Cat(), Dog()):
pet.speak()
Python calls the correct method automatically based on object type.
9) MRO — Method Resolution Order
class A: pass
class B(A): pass
class C(B): pass
print(C.mro())
MRO tells Python which parent to look in first when resolving methods.
10) Abstract Classes & Interfaces (abc)
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def pay(self, amount):
pass
class PayPal(Payment):
def pay(self, amount):
print("Paid using PayPal")
11) Composition (HAS-A) vs Inheritance (IS-A)
Composition Example
class Engine:
def start(self):
print("Engine start")
class Car:
def __init__(self):
self.engine = Engine() # has-a
def start(self):
self.engine.start()
12) Dataclasses — Simple Models
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: float
p = Product("Laptop", 1200)
print(p)
13) Useful Magic Methods
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)
14) Three Common Design Patterns
1) Singleton
class Singleton:
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
2) Factory
class ShapeFactory:
def get_shape(self, type):
if type == "circle": return Circle()
if type == "square": return Square()
3) Strategy Pattern
class JSONStrategy:
def process(self, data): ...
class XMLStrategy:
def process(self, data): ...
15) Mini Real-World Project: Tiny Billing System
from dataclasses import dataclass
@dataclass
class Item:
name: str
price: float
class Cart:
def __init__(self):
self.items = []
def add(self, item: Item):
self.items.append(item)
def total(self):
return sum(i.price for i in self.items)
cart = Cart()
cart.add(Item("Keyboard", 3000))
cart.add(Item("Mouse", 1500))
print("Total:", cart.total())
Key Takeaways
- OOP models real-world concepts using classes and objects.
__init__initializes objects;selfrefers to each instance.- Instance methods, class methods, and static methods serve different roles.
- Inheritance allows code reuse; polymorphism enables flexible behavior.
- Use abstract classes to define “rules” for subclasses.
- Prefer composition over inheritance for cleaner design.
- Magic methods let you customize how objects behave.
- Dataclasses provide clean, concise models.
- Design patterns help build scalable applications.
Leave a comment
Your email address will not be published. Required fields are marked *
