Absolutely π Let’s understand OOPs in Python in the easiest possible way, with simple real-life examples.
π OOPs in Python
OOP = Object-Oriented Programming
Think of OOP as creating a blueprint and then creating real things from that blueprint.
Real-life example
Suppose Car is a blueprint.
A car has:
- Properties: color, brand, speed
- Actions: start(), stop(), drive()
In Python:
class Car: def __init__(self, color, brand): self.color = color self.brand = brand def drive(self): print("Car is driving") car1 = Car("Red", "BMW") print(car1.color) print(car1.brand) car1.drive()
Output:
Red BMW Car is driving
1. Class
A class is a blueprint/template.
class Student: pass
Here, Student is a class.
Think:
Class = Blueprint
2. Object
An object is a real instance of a class.
class Student: pass student1 = Student() student2 = Student()
Here:
-
Student→ Class -
student1→ Object -
student2→ Object
Think:
Class = House blueprint
Object = Actual house
3. __init__() Constructor
__init__() runs automatically when we create an object.
class Student: def __init__(self, name, age): self.name = name self.age = age student1 = Student("Rahul", 20) print(student1.name) print(student1.age)
Output:
Rahul 20
What is self?
self means the current object.
self.name = name
Means:
Store
nameinside this particular object.
4. Encapsulation
Encapsulation = keeping data and methods together inside a class.
Example:
class BankAccount: def __init__(self, balance): self.balance = balance def deposit(self, amount): self.balance += amount account = BankAccount(1000) account.deposit(500) print(account.balance)
Output:
1500
The balance and the functions that work on it are kept inside BankAccount.
5. Inheritance
Inheritance = child class gets properties/methods from parent class.
Real-life example:
Animal → Dog
Dog is an Animal.
class Animal: def eat(self): print("Animal is eating") class Dog(Animal): def bark(self): print("Dog is barking") dog = Dog() dog.eat() dog.bark()
Output:
Animal is eating Dog is barking
Dog inherited eat() from Animal.
Think:
Parent → Child
6. Polymorphism
Polymorphism = same method name, different behavior.
Example:
class Dog: def sound(self): print("Dog says Woof") class Cat: def sound(self): print("Cat says Meow") dog = Dog() cat = Cat() dog.sound() cat.sound()
Output:
Dog says Woof Cat says Meow
Same method:
sound()
Different behavior.
Think:
One name → Many forms
7. Abstraction
Abstraction = hiding unnecessary details and showing only what is needed.
For example, when you drive a car:
You use:
Start Accelerator Brake Steering
You don't need to know exactly how the engine works internally.
Python example:
from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def sound(self): pass class Dog(Animal): def sound(self): print("Woof") dog = Dog() dog.sound()
Output:
Woof
⭐ Four Main Pillars of OOP
Remember these four:
| OOP Concept | Easy Meaning |
|---|---|
| Encapsulation | Keep data + methods together |
| Inheritance | Child gets features from parent |
| Polymorphism | Same method, different behavior |
| Abstraction | Hide unnecessary implementation |
π§ Interview shortcut
E → I → P → A
Encapsulation → Inheritance → Polymorphism → Abstraction
And remember:
Class = Blueprint
Object = Real thing
__init__= Constructor
self= Current object
Sure π Here is a simple English explanation of the four pillars of OOP in Python, with easy examples.
OOPs: Four Main Pillars
Remember:
E → I → P → A
- E — Encapsulation
- I — Inheritance
- P — Polymorphism
- A — Abstraction
1. Encapsulation
Meaning
Encapsulation means keeping data and the methods that work on that data together inside a class.
It also helps protect data from being directly changed from outside.
Example
class BankAccount: def __init__(self, balance): self.__balance = balance def deposit(self, amount): self.__balance += amount def get_balance(self): return self.__balance account = BankAccount(1000) account.deposit(500) print(account.get_balance())
Output:
1500
Here:
-
__balanceis private. - We don't directly access it.
-
We use
deposit()andget_balance()to work with it.
Easy to remember:
Encapsulation = Data hiding + Data protection
2. Inheritance
Meaning
Inheritance means a child class can use the properties and methods of a parent class.
Example
class Animal: def eat(self): print("Animal is eating") class Dog(Animal): def bark(self): print("Dog is barking") dog = Dog() dog.eat() dog.bark()
Output:
Animal is eating Dog is barking
Dog gets the eat() method from Animal.
Easy diagram
Animal ↓ Dog
Easy to remember:
Inheritance = Reuse code from parent class
Types of Inheritance
There are 5 common types in Python.
1. Single Inheritance
One parent → One child
class Animal: def eat(self): print("Eating") class Dog(Animal): def bark(self): print("Barking") dog = Dog() dog.eat() dog.bark()
Animal ↓ Dog
2. Multiple Inheritance
One child → Multiple parents
class Father: def skills(self): print("Driving") class Mother: def talent(self): print("Cooking") class Child(Father, Mother): pass child = Child() child.skills() child.talent()
Father ──┐ ↓ Child ↑ Mother ──┘
3. Multilevel Inheritance
Grandparent → Parent → Child
class Grandfather: def house(self): print("Has a house") class Father(Grandfather): def car(self): print("Has a car") class Son(Father): def bike(self): print("Has a bike") son = Son() son.house() son.car() son.bike()
Grandfather ↓ Father ↓ Son
4. Hierarchical Inheritance
One parent → Multiple children
class Animal: def eat(self): print("Eating") class Dog(Animal): def bark(self): print("Barking") class Cat(Animal): def meow(self): print("Meowing") dog = Dog() cat = Cat() dog.eat() cat.eat()
Animal / \ Dog Cat
5. Hybrid Inheritance
Combination of two or more types of inheritance.
class A: def show_a(self): print("A") class B(A): def show_b(self): print("B") class C(A): def show_c(self): print("C") class D(B, C): def show_d(self): print("D") obj = D() obj.show_a() obj.show_b() obj.show_c() obj.show_d()
A / \ B C \ / D
3. Polymorphism
Meaning
Polymorphism means "one name, many forms."
The same method can behave differently depending on the object.
Example
class Dog: def sound(self): print("Woof") class Cat: def sound(self): print("Meow") dog = Dog() cat = Cat() dog.sound() cat.sound()
Output:
Woof Meow
Both classes have:
sound()
But they behave differently.
Easy to remember:
Polymorphism = Same method, different behavior
Types/Forms of Polymorphism in Python
1. Method Overriding
Child class changes the behavior of a parent method.
class Animal: def sound(self): print("Animal makes sound") class Dog(Animal): def sound(self): print("Dog says Woof") dog = Dog() dog.sound()
Output:
Dog says Woof
The child Dog overrides the parent sound().
2. Duck Typing
Python focuses on what an object can do, rather than its exact type.
class Dog: def sound(self): print("Woof") class Cat: def sound(self): print("Meow") def make_sound(animal): animal.sound() make_sound(Dog()) make_sound(Cat())
Output:
Woof Meow
The function doesn't care whether it receives a Dog or Cat.
It only cares that the object has a sound() method.
4. Abstraction
Meaning
Abstraction means hiding implementation details and showing only the important functionality.
Real-life example:
When you use an ATM:
Insert Card ↓ Enter PIN ↓ Withdraw Money
You don't need to know how the bank's internal system processes the transaction.
Python Example
from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def sound(self): pass class Dog(Animal): def sound(self): print("Woof") dog = Dog() dog.sound()
Output:
Woof
Animal says:
Every animal must have a
sound()method.
But it doesn't specify exactly how the sound should be produced.
Dog provides the actual implementation.
Easy to remember:
Abstraction = Hide implementation + Show necessary functionality
⭐ Final Interview Revision
| Concept | Simple Meaning | Example |
|---|---|---|
| Encapsulation | Protect/hide data | Bank Account |
| Inheritance | Reuse parent code | Animal → Dog |
| Polymorphism | Same method, different behavior | Dog/Cat → sound() |
| Abstraction | Hide implementation details | ATM / Abstract Class |
π§ One-line trick
Encapsulation → Protect data
Inheritance → Reuse code
Polymorphism → Different behavior
Abstraction → Hide details
If you're preparing for a Python interview, these four plus class, object, self, __init__, method overriding, and super() are the core OOP topics to know.
Yes π In OOP, Polymorphism is commonly explained in two forms:
- Compile-time Polymorphism
- Run-time Polymorphism
But there is an important point for Python: Python is dynamically typed and does not have traditional compile-time method overloading like Java/C++. Python mainly achieves polymorphism at runtime.
1. Compile-Time Polymorphism
Meaning
The method or operation to use is determined during compilation.
A common example is Method Overloading.
Example in Java/C++
add(int, int) add(int, int, int)
The compiler decides which add() method should be called based on the number/type of arguments.
What about Python?
Python does not support traditional method overloading.
For example, this does not work as expected:
class Calculator: def add(self, a, b): return a + b def add(self, a, b, c): return a + b + c
The second add() replaces the first one.
Instead, Python can achieve similar behavior using default arguments:
class Calculator: def add(self, a, b, c=0): return a + b + c calculator = Calculator() print(calculator.add(10, 20)) print(calculator.add(10, 20, 30))
Output:
30 60
So, in a Python interview, say:
Python does not support traditional compile-time method overloading. We can achieve similar behavior using default arguments,
*args, etc.
2. Run-Time Polymorphism
Meaning
The method that will execute is determined at runtime, depending on the object.
The most common example is Method Overriding.
class Animal: def sound(self): print("Animal makes a sound") class Dog(Animal): def sound(self): print("Dog says Woof") class Cat(Animal): def sound(self): print("Cat says Meow") animals = [Dog(), Cat()] for animal in animals: animal.sound()
Output:
Dog says Woof Cat says Meow
Here:
animal.sound()
is the same method call, but Python decides at runtime which version to execute.
Easy diagram
Animal sound() / \ / \ Dog Cat sound() sound() ↓ ↓ Woof Meow
This is Run-Time Polymorphism → Method Overriding.
⭐ Compile-Time vs Run-Time
| Feature | Compile-Time | Run-Time |
|---|---|---|
| Decision made | During compilation | During execution |
| Common example | Method Overloading | Method Overriding |
| Python support | ❌ No traditional overloading | ✅ Yes |
| Example | add(a,b) / add(a,b,c) | Dog.sound() / Cat.sound() |
π§ Interview Answer
If interviewer asks "What are the types of polymorphism?", you can say:
There are two common types: compile-time polymorphism and run-time polymorphism. Compile-time polymorphism is usually achieved through method overloading, while run-time polymorphism is achieved through method overriding. Python does not support traditional compile-time method overloading, but it supports run-time polymorphism very well through method overriding and duck typing.
No. You cannot define multiple __init__() methods in the same Python class and have all of them work.
If you write multiple __init__() methods, the last one replaces the previous one.
❌ Example
class Car: def __init__(self, color): self.color = color def __init__(self, color, brand): self.color = color self.brand = brand car = Car("Red", "BMW")
Python uses only the second __init__().
The first one is overwritten.
✅ How to handle different numbers of arguments
Use default arguments:
class Car: def __init__(self, color, brand=None): self.color = color self.brand = brand car1 = Car("Red") car2 = Car("Blue", "BMW") print(car1.color) print(car2.color, car2.brand)
Output:
Red Blue BMW
So you can create objects in different ways without creating multiple __init__() methods.
impportant points :
Great question π self is one of the most important concepts in Python OOP.
What is self?
self refers to the current object.
In simple words:
selftells Python which object's data or method you are talking about.
Example
class Car: def __init__(self, color, brand): self.color = color self.brand = brand def drive(self): print(self.brand, "is driving") car1 = Car("Red", "BMW") car2 = Car("Blue", "Audi") print(car1.color) print(car2.color) car1.drive() car2.drive()
Output:
Red Blue BMW is driving Audi is driving
Why do we need self?
Look at this:
self.color = color
There are two different colors:
color → value received by __init__() self.color → value stored inside the object
When we do:
car1 = Car("Red", "BMW")
Python creates:
car1 ├── color = "Red" └── brand = "BMW"
When we do:
car2 = Car("Blue", "Audi")
Python creates another object:
car2 ├── color = "Blue" └── brand = "Audi"
self makes this possible.
Think of self as "my"
Imagine car1 says:
My color is Red.
Python represents "my" using self:
self.color = color
For car1:
self → car1
For car2:
self → car2
So:
car1.drive()
means approximately:
drive(car1)
and:
car2.drive()
means approximately:
drive(car2)
Why self in every method?
class Car: def drive(self): print(self.brand) def stop(self): print(self.brand, "stopped")
self allows the method to access the specific object's attributes.
Without self, Python wouldn't know which object's brand you mean.
π§ Remember this
self = current object
car1 → self car2 → self car3 → self
The same class can create thousands of objects, and self tells Python which object is currently being used.
Comments
Post a Comment