Hi, My name is Samiksha and this blog gives a beginner-friendly guide to Classes, Objects, init(), self, Attributes, Inheritance, Method Overriding & super()
When I started learning Python for backend development, I came across Object-Oriented Programming (OOP).
The definitions sounded simple:
"A class is a blueprint."
"An object is an instance of a class."
I understood the definitions, but I didn't feel like I actually understood what was happening.
So instead of memorizing the terminology, I decided to understand OOP through small examples and, more importantly, understand why we use these concepts in real backend development.
This is what finally made OOP click for me.
What is OOP?
OOP stands for Object-Oriented Programming.
It is a programming approach where we organize our code around **objects **that contain:
- Data
- Behavior
For example, in a backend application we might have a User.
A user can have data like:
name
email
age
and behavior like:
login()
logout()
update_profile()
Instead of keeping everything separate, OOP allows us to group related data and functionality together.
1. Classes
A class can be thought of as a structure or blueprint for creating objects.
For example:
class Student:
pass
Here, Student is a class.But the class itself isn't a particular student.
It defines what a Student object can look like.
2. Objects
An object is an actual instance created from a class.
class Student:
pass
student1 = Student()
student2 = Student()
Here:
Student → Class
student1 → Object
student2 → Object
Both objects belong to the Student class, but they are separate objects.
This distinction became much clearer to me when I started thinking about it like this:
Class
↓
Blueprint
Object
↓
Actual thing created using that blueprint
3. init() — The Special Method
This was one of the things I initially found confusing.
Consider:
class Student:
def init(self, name, age):
self.name = name
self.age = age
Now:
student1 = Student("Samiksha", 24)
We didn't explicitly call:
student1.init()
But Python automatically calls init() when the object is initialized.
So:
student1 = Student("Samiksha", 24)
causes the initialization code to run.
The purpose of init() is mainly to initialize the object's data.
For example:
self.name = name
self.age = age
sets the initial values for that particular object.
Important:
*init() is not something we write inside every function.
*
It is a special method defined inside a class that runs automatically when an object is initialized.
4. What is self?
This was probably the most important thing for me to understand.
Consider:
class Student:
def init(self, name, age):
self.name = name
self.age = age
And:
student1 = Student("Samiksha", 24)
Here, self refers to the current object. So when we have:
self.name = name
we are basically saying:
Store this name inside the current object's name attribute.
For student1, it becomes conceptually:
student1
|
├── name → "Samiksha"
└── age → 24
If we create another object:
student2 = Student("Rahul", 22)
then self refers to student2 during that initialization.
So:
student1 → Samiksha, 24
student2 → Rahul, 22
The same class creates different objects with different data.
5. Methods
A function defined inside a class is called a method.
Example:
class Student:
def init(self, name):
self.name = name
def introduce(self):
return f"My name is {self.name}"
Now:
student = Student("Samiksha")
print(student.introduce())
Output:
My name is Samiksha
Here:
introduce()
is a method of the Student class.
And:
self.name
refers to the name belonging to the current object.
6. Instance Attributes
Now let's understand attributes.
In this code:
class Student:
def init(self, name, age):
self.name = name
self.age = age
name and age are instance attributes.
Why?
Because every object can have its own values.
student1 = Student("Samiksha", 24)
student2 = Student("Rahul", 22)
We get:
student1
├── name → Samiksha
└── age → 24
student2
├── name → Rahul
└── age → 22
So:
Instance attributes belong to individual objects.
7. Class Attributes
Now imagine every student belongs to the same college.
We don't need to store the same college separately for every object.
We can define a class attribute:
class Student:
college = "ABC University"
def __init__(self, name):
self.name = name
Now:
student1 = Student("Samiksha")
student2 = Student("Rahul")
print(student1.college)
print(student2.college)
Output:
ABC University
ABC University
Here:
college = "ABC University"
is a class attribute.
While:
self.name = name
is an instance attribute.
The simple difference:
Instance Attribute
→ belongs to an individual object
Class Attribute
→ belongs to the class and can be shared by its objects
8. Inheritance
Now comes one of the most useful OOP concepts: Inheritance.
Inheritance allows one class to reuse properties and methods from another class.
Example:
class Animal:
def eat(self):
print("Eating")
class Dog(Animal):
def bark(self):
print("Barking")
Now:
dog = Dog()
dog.eat()
dog.bark()
Output:
Eating
Barking
But we never defined eat() inside Dog.
Why does it work?
Because:
Animal
↓
Inheritance
↓
Dog
Dog inherits the eat() method from Animal.
Here:
Animal → Parent Class
Dog → Child Class
9. Method Overriding
A child class can also provide its own implementation of a method inherited from the parent.
Example:
class User:
def login(self):
print("User login")
class Admin(User):
def login(self):
print("Admin login")
Now:
user = User()
admin = Admin()
user.login()
admin.login()
Output:
User login
Admin login
The Admin class has overridden the login() method inherited from User.
So:
Method overriding means a child class provides its own implementation of a method that already exists in the parent class.
10. super()
Another concept that became important after understanding inheritance is super().
Suppose:
class User:
def init(self, name):
self.name = name
class Admin(User):
def init(self, name, role):
super().init(name)
self.role = role
Now:
admin = Admin("Samiksha", "Administrator")
We can access:
print(admin.name)
print(admin.role)
Output:
Samiksha
Administrator
So what did:
super().init(name)
do?
It called the parent class's init() method.
Conceptually:
Admin
│
├── super().init(name)
│ ↓
│ User.init()
│ ↓
│ self.name = name
│
└── self.role = role
So super() allows the child class to reuse functionality from its parent.
11. Why does OOP matter for Backend Development?
At first, OOP can feel like just another Python topic.
But when working with backend systems, we frequently deal with entities such as:
User
Student
Scholarship
Donation
Payment
Organization
These entities have:
Data
Relationships
Behaviors
For example, a User might have:
name
email
password
and functionality such as:
login()
logout()
update_profile()
Later, when working with frameworks and tools like FastAPI and SQLAlchemy, understanding classes, objects, attributes, inheritance, and methods becomes much more useful.
For example, database models are commonly represented using classes.
That's one of the reasons understanding OOP properly is important before moving deeper into backend development.
My OOP Cheat Sheet
After learning these concepts, this is how I now remember them:
Class
↓
Blueprint / structure
Object
↓
Instance of a class
init()
↓
Runs during object initialization
self
↓
Current object
Method
↓
Function defined inside a class
Instance Attribute
↓
Object-specific data
Class Attribute
↓
Data associated with the class
Inheritance
↓
Child class reuses parent functionality
Method Overriding
↓
Child provides its own version of a parent method
super()
↓
Access/reuse parent class functionality
One thing I learned while studying OOP is that understanding is much more valuable than memorizing definitions.
If someone had asked me earlier:
"What is self?"
I could probably have given the textbook answer.
But now I can actually visualize it:
self
↓
current object
And that small shift—from remembering a definition to understanding what the code is actually doing—is what I'm trying to focus on as I continue learning backend development.

