Object Oriented Programming Python Tutorial, Step by Step: learn OOP in Python. Videos, Notes, and Practical Examples are Included. Read Below Blog 🙂
🔹 What is Object Oriented Programming (OOP)?
OOP (Object-Oriented Programming) is a way to write code by creating objects that represent real-world things.
🧠 Real-life example:
Imagine you’re designing a car. You don’t describe each car from scratch. You define a blueprint (class), and then you can make many cars (objects) using that blueprint.
💡 Simple definition:
“OOP helps organize code by grouping related data and actions into objects.”
✅ Why do we use Object Oriented Programming Python?
Because it helps us write code that is:
- 1. Organized 📦
- We group related data and actions into one place (a class), like packing everything about a “Car” in one box.
- 2. Reusable 🔁
- Once we create a class (blueprint), we can make many objects from it — no need to write the same code again and again.
- 3. Easier to Maintain 🛠️
- If something breaks or needs an update, we only change it in one place — inside the class — not everywhere in the code.
- 4. Real-World Modeling 🌍
- We can write code that looks like real-life things — like “Person”, “Dog”, “Account”, etc. — making it easier to understand.
- 5. Safe 🔐
- We can hide sensitive information inside a class (encapsulation), like hiding your bank balance from direct access.
🧠 Analogy:
Think of OOP like Lego blocks — once you build a block (class), you can reuse it, extend it, or protect parts of it — instead of rebuilding every time.
🧠 Core Types of Object Oriented Programming Python
Yes, OOP is built on two main things inside every class:
Part | Also Called | What it Represents | Example |
---|---|---|---|
Attributes | Properties / Data | What the object has | name , age , balance |
Methods | Functions / Behavior | What the object does | deposit() , greet() |
✅ Real-Life Analogy: Dog
class Dog:
def __init__(self, name, breed): # Attributes
self.name = name
self.breed = breed
def bark(self): # Method
print(f"{self.name} says Woof!")
- Attributes:
name
,breed
→ what the dog has - Method:
bark()
→ what the dog does
🧱 Evergreen OOP Structure (Starter Formula)
Let me give you the evergreen, basic structure of OOP in Python — the one you can always follow when creating your own classes.
class ClassName: def __init__(self, attribute1, attribute2): self.attribute1 = attribute1 self.attribute2 = attribute2 def method1(self): # Do something using self.attribute1 or self.attribute2 pass def method2(self): # Another action pass # Creating object obj = ClassName(value1, value2) # Using method obj.method1()
🧪 Example: Student Class
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def show_info(self):
print(f"Name: {self.name}, Grade: {self.grade}")
# Create object
s1 = Student("Aman", "A")
# Use method
s1.show_info()
🧠 Always Remember This Pattern:
class
→ defines the blueprint__init__()
→ constructor to set up dataself
→ refers to the current objectmethods
→ define behavior/actionsobject
→ actual item created from class
🔑 What is self
in Python OOP?
🧠 Simple Definition:
self
is like saying “me” inside the object — it lets the object refer to its own data and actions.
🚘 Car Example:
Imagine you have 2 cars: one red, one black.
Each car needs to know its own color.
class Car:
def __init__(self, color):
self.color = color # "self" means: this car's color
def show_color(self):
print(f"My color is {self.color}")
self.color
means “this car’s color”- So, if
car1
is red andcar2
is black, each one knows its own color
👨💼 Friend Example:
class Friend:
def __init__(self, name):
self.name = name # "self" refers to this friend
def greet(self):
print(f"Hi! I am {self.name}")
- When you create 2 friends (
Anu
,Vivek
),self.name
ensures each friend introduces themselves correctly.
📚 Book Example:
class Book:
def __init__(self, title):
self.title = title # "self" refers to the specific book
def read(self):
print(f"You're reading '{self.title}'")
- If one book is “Harry Potter” and another is “Atomic Habits”,
self.title
keeps the correct identity for each book.
🔁 Analogy:
Think of self as the word “I” or “my” that each object uses to talk about itself.
A book says: “I am Atomic Habits”
A friend says: “I am Rahul”
A car says: “My color is red”
They say this using self
.
🔹 Is self
a default value?
Yes ✅ — self
is the conventionally used name, but you can technically rename it to anything (like this
, abc
, etc.).
However, you should not change it — because:
self
is the Python standard- Everyone understands it
- It keeps your code readable and maintainable
🛑 So: Don’t change it, even though Python allows it.
❗ What happens if you don’t use self
?
➤ 1. You can’t access attributes
If you skip self
, Python won’t know you’re referring to the object’s own data.
class Car:
def __init__(color): # ❌ No self
color = color
def show_color():
print(color) # ❌ Will give NameError
Output:
NameError: name 'color' is not defined
Python thinks color
is a local variable, not an attribute of the object.
➤ 2. You’ll get TypeError
If you try to define a method without self
, calling it will throw an error:
class Car:
def start_engine(): # ❌ missing self
print("Engine started")
my_car = Car()
my_car.start_engine() # ❌ ERROR
Output:
TypeError: start_engine() takes 0 positional arguments but 1 was given
Because when you do my_car.start_engine()
, Python automatically passes the object as the first argument — and it expects that to be self
.
✅ Summary:
Situation | Result |
---|---|
Don’t use self in attributes | Can’t access object data |
Don’t use self in methods | TypeError: takes 0 but 1 given |
Rename self to something else | Technically works but not recommended |
🔍 What is __str__()
In Object Oriented Programming Python?
🔹 Definition:
__str__()
is a special method in Python used to define what should be printed when you do:
print(object_name)
🧠 Why use it?
Without __str__()
, printing an object gives you this:
<__main__.Car object at 0x000001>
But with __str__()
, you get a nice readable message instead.
💬 Analogy:
Imagine someone asks:
“Tell me about your friend.”
You wouldn’t say:
“Object located at 0xGHF003X”
Instead, you’d say:
“His name is Rahul, he’s 25 years old.”
That’s exactly what __str__()
does — it returns a friendly summary of the object.
✅ Syntax:
def __str__(self):
return "Custom string here"
✅ Evergreen Template for __str__()
class ClassName: def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2 def __str__(self): return f"Summary of {self.attr1}, {self.attr2}"
Use this in every class to make printed objects readable.
🆚 __str__()
vs Custom Methods
Feature | __str__() | Custom Methods (start_engine() , greet() , etc.) |
---|---|---|
Purpose | Used to define how the object looks when printed | Used to define custom behaviors or actions |
Triggers | Automatically called when using print(object) | Manually called like object.method() |
Return | Always returns a string | May return something or just print something |
Typical Use | To summarize object data in 1 line | To perform actions like calculations, greetings, etc. |
Built-in? | Yes, special built-in method | No, you define as per your need |
✅ When to Use __str__()
Use it when:
- You want to print the object and see a clean summary.
- You want easy debugging.
- You’re teaching or learning — makes object output readable.
🔁 Example: __str__()
for Book
print(my_book)
# Output: Book: 'Atomic Habits' by James Clear
Without __str__()
, this would just give a confusing memory address.
✅ When to Use Custom Methods
Use them when:
- You want the object to do something, not just represent itself.
- Examples:
- Start a car
- Greet a person
- Calculate price
- Update a record
🔁 Example: Custom Method for Car
tiago.start_engine()
# Output: The Black car's engine has started
This is an action, not a summary.
📌 Summary Table
Task | Use | Why |
---|---|---|
Show object info on print() | __str__() | Gives readable summary of object |
Make the object “do” something | Custom method | Performs specific action/behavior |
✅ Example Recap: Combined Structure
You can (and should) combine __str__()
and custom methods in the same class. They work together perfectly but serve different purposes:
class Car:
def __init__(self, color, model, price):
self.color = color
self.model = model
self.price = price
def __str__(self):
return f"Car Model: {self.model}, Color: {self.color}, Price: ₹{self.price}" # Used when you do print(car)
def start_engine(self):
print(f"{self.model}'s engine has started.") # Custom behavior
def stop(self):
print(f"{self.model} has stopped.") # Another custom behavior
You can now do:
tiago = Car("Red", "XE", 560000)
print(tiago) # 🔁 Calls __str__()
tiago.start_engine() # ▶️ Calls your custom method
tiago.stop() # ▶️ Another custom method
💡 Use Cases:
Action | What Happens |
---|---|
print(tiago) | Shows car summary using __str__() |
tiago.start_engine() | Starts engine using your method |
tiago.stop() | Stops the car |
🔐 What is Encapsulation in Object Oriented Programming Python?
Encapsulation means:
Hide the data inside the class, and control how it’s seen (getter) and changed (setter).
And with getter-only, you allow people to see the value, but not change it.
🧠 Analogy:
Think of an ATM machine:
- You see your balance (getter ✅)
- You update your PIN or withdraw cash (setter ✅)
- But you cannot touch the bank database directly (private data ❌)
✅ Why Use Getter Only?
- Protects sensitive or read-only data
- Prevents outside tampering
- Gives control over how data is shown
🎯 Why Use Setter?
- To update private data safely
- To validate new values before accepting
- To keep your program clean and secure
🌱 Evergreen Template for Getter Only
class ClassName: def __init__(self, data): self.__data = data # 🔐 Private variable def get_data(self): return self.__data # ✅ Only getter
🌱 Evergreen Template for Getter & Setter Both
class ClassName: def __init__(self, data): self.__data = data def get_data(self): return self.__data def set_data(self, new_data): if new_data is valid: self.__data = new_data else: print("❌ Invalid value")
🚘 Example: Car Class
class Car:
def __init__(self, model, price):
self.model = model
self.__price = price # 🔐 Private
def get_price(self):
return self.__price # ✅ Getter
car1 = Car("XE", 560000)
print(car1.model) # ✅ OK
print(car1.get_price()) # ✅ OK
print(car1.__price) # ❌ Error: cannot access private variable
🧩 Summary:
Feature | Role |
---|---|
__variable | Private, cannot be touched |
get_...() | Safely shows the value |
🔰 What is Inheritance in Object Oriented Programming Python?
Inheritance means one class (child) can reuse the code from another class (parent).
It helps you avoid repeating code and makes your program clean and organized.
🧩 Real-Life Analogy:
- Parent = Phone
- Can call 📞, text 📩
- Child = Smartphone
- Can call, text (inherited) + use apps, take photos 📱
The smartphone inherits from phone but also adds its own features.
🔑 What is super().__init__()
?
It’s a way for the child class to call the constructor of the parent class.
🧠 Simple Meaning:
“Hey Parent, I’m a child class. Please run your setup code (constructor) for me too!”
🧱 Evergreen Template:
class ParentClass:
def __init__(self, attribute1, attribute2):
self.attribute1 = attribute1
self.attribute2 = attribute2
def method1(self):
# Some action
pass
class ChildClass(ParentClass): # Inheriting
def __init__(self, attribute1, attribute2, new_attribute):
super().__init__(attribute1, attribute2) # Call parent constructor
self.new_attribute = new_attribute
def child_method(self):
# Extra method for child
pass
# Create object
obj = ChildClass("value1", "value2", "extra")
obj.method1() # From Parent
obj.child_method() # From Child
🔄 Summary:
Term | Meaning |
---|---|
Parent | Base class with common features |
Child | Derived class that adds new stuff |
super() | Used to call parent’s constructor |
Benefit | Reuse code, organize better |
🧠 What is Polymorphism Object Oriented Programming Python?
Polymorphism means “many forms”.
In Python, it allows the same method name to behave differently depending on the object.
🎯 Real-Life Analogy:
- You say
start()
to a car, and it starts the engine - You say
start()
to a book, and it starts the reading - You say
start()
to a friend, and it starts a conversation
Same method name, different behaviors depending on the object = Polymorphism
✅ Evergreen Template:
class A:
def action(self):
print("Action from A")
class B:
def action(self):
print("Action from B")
# Polymorphism in action
def perform_action(obj):
obj.action()
obj1 = A()
obj2 = B()
perform_action(obj1) # Output: Action from A
perform_action(obj2) # Output: Action from B
🔁 Summary:
- Same method name (like
start()
,greet()
) - Different class = different result
- Useful for code flexibility and avoiding repeated code
🧠 What is Abstraction in Object Oriented Programming Python?
Abstraction means hiding complex details and showing only what’s needed.
Think of it as using a car — you only press the accelerator, brake, and steering,
but don’t worry about the engine mechanics behind it.
🎯 Simple Definition:
In Python, abstraction is achieved using abstract classes (via ABC
and @abstractmethod
) to define blueprints.
You can’t create objects of abstract classes — only of the child classes that complete the blueprint.
📦 Evergreen Template:
from abc import ABC, abstractmethod
class Blueprint(ABC):
@abstractmethod
def required_method(self):
pass
class Concrete(Blueprint):
def required_method(self):
print("Implemented in child class")
obj = Concrete()
obj.required_method()
🧩 Summary:
Concept | Meaning |
---|---|
Abstraction | Hide complex code, show only essentials |
How? | Use abstract class (ABC ) + abstract method |
Why? | Forces consistency and clean design |
Key Rule | You must implement all abstract methods in child class |
Recap: Object Oriented Programming Python 🧠✨
Here’s your complete OOP recap in the clearest way possible — with real-life analogies and consistent structure
✅ 1. Class & Object
🔹 Concept:
- Class = Blueprint
- Object = Real instance of that blueprint
🧠 Analogy:
- Class = ChatGPT Prompt
- Object = Each unique response/output generated
✅ 2. Attributes & Methods
🔹 Concept:
- Attributes = Data (e.g. color, price)
- Methods = Actions (e.g. start_engine, drive)
🧠 Analogy:
- Car has color and model → Attributes
- Car can drive or stop → Methods
✅ 3. The self
Keyword
🔹 Concept:
Refers to the current object
Used to access that object’s attributes and methods
🧠 Analogy:
“I” refers to yourself — self.color
= my color
✅ 4. __str__()
Method
🔹 Concept:
Gives a custom print output for your object
🧠 Analogy:
Your resume’s summary line — a neat way to introduce yourself when someone prints your details
✅ 5. Encapsulation
🔹 Concept:
Hide sensitive data using private variables (__price
)
Access/control via getters and setters
🧠 Analogy:
ATM — you can’t directly grab money inside; you use buttons (methods) to withdraw/deposit
✅ 6. Inheritance
🔹 Concept:
Child class inherits attributes and methods from Parent
🧠 Analogy:
ElectricCar inherits Car’s properties but adds its own — like battery life
class Parent:
def __init__(...): ...
class Child(Parent):
def __init__(...):
super().__init__(...) # calls parent setup
✅ 7. Polymorphism
🔹 Concept:
Same method name, different behavior across classes
🧠 Analogy:
start()
on a Car = start enginestart()
on a Book = open bookstart()
on a Friend = start talking
✅ 8. Abstraction
🔹 Concept:
Hide complexity using abstract base classes
Force child classes to implement required methods
🧠 Analogy:
A power plug = you use only what you need (plug in), not how wires run inside walls
from abc import ABC, abstractmethod
class Blueprint(ABC):
@abstractmethod
def method(self): pass
🚀 Summary Table:
Concept | Keyword/Tool | Real-Life Analogy |
---|---|---|
Class/Object | class , object() | Prompt → Response |
Attributes | self.value | Car color, Book title |
Methods | def method() | Car drives, Friend greets |
self | self | “I”, “My” inside the object |
str | def __str__() | Resume one-liner for object |
Encapsulation | __private , get/set | ATM buttons for money |
Inheritance | class Child(Parent) | Child inherits traits from Parent |
Polymorphism | same method() | start() works differently per object |
Abstraction | ABC , @abstractmethod | Power plug with simple interface |