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:
selfis 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.colormeans โthis carโs colorโ- So, if
car1is red andcar2is 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.nameensures 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.titlekeeps 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:
selfis 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 |

