OOPs in Python
What is Object-Oriented Programming (OOPs)?
Object-Oriented Programming (OOPs) is a programming paradigm in Python where
code is organized around objects and classes. These objects represent real-world
entities by combining data (attributes) and behavior (methods) into one unit.
Why is OOPs Used in Python?
• Helps model real-world systems easily
• Improves code reusability through inheritance
• Enhances modularity, readability, and maintenance
• Makes it easier to manage and extend large codebases
• Provides structure to the code by bundling data and operations
together
Evolution of Programming Paradigms
Paradigm Description Examples
Procedural Code is written as sequences of instructions or
C, Pascal
Programming procedures (functions).
Functional Emphasizes use of pure functions, immutability, Haskell,
Programming and avoids state changes. early Python
Object-Oriented Organizes code using objects and classes, Python, Java,
Programming modeling real-world systems. C++
Four Pillars of OOPs in Python
1. Encapsulation
Encapsulation is the concept of wrapping data and methods into a single unit
(class), while restricting direct access to some of the object’s components.
class Person:
def __init__(self, name):
self.__name = name # Private variable
def get_name(self):
return self.__name
2. Abstraction
Abstraction means hiding complex implementation details and exposing only
the essential features of an object.
from abc import ABC, abstractmethod
class Vehicle(ABC):
@abstractmethod
def start_engine(self):
pass
3. Inheritance
Inheritance allows a class to inherit properties and methods from another
class. It promotes code reuse.
class Animal:
def speak(self):
print("Animal sound")
class Dog(Animal):
def speak(self):
print("Bark")
4. Polymorphism
Polymorphism allows different classes to use the same interface or method
name in different ways.
def make_sound(animal):
[Link]()
make_sound(Dog()) # Output: Bark
make_sound(Animal()) # Output: Animal sound
In [49]: # proceedural programming
# data store
name1='Vipul'
course1='Data Analytics'
name2='Ram'
course2='Data science'
In [50]: # functional programming
# function-->
def info(**kwargs):
return kwargs
In [51]: info(name='Anshum',course='Data analytics')
Out[51]: {'name': 'Anshum', 'course': 'Data analytics'}
In [52]: #OPP
#class
#object
#feature-->attributes\
#function-->method
class Skillcircle:
name='Vipul'
course='Data Analyst'
age=19
def info(self):
print('name\t',[Link])
print('course\t',[Link])
print('age\t',[Link])
In [53]: #obj
stud1=Skillcircle()
stud2=Skillcircle()
In [54]: [Link]
Out[54]: 'Vipul'
In [55]: [Link]
Out[55]: 'Data Analyst'
In [56]: [Link]
Out[56]: 19
In [57]: [Link]()
name Vipul
course Data Analyst
age 19
In [58]: [Link]='Ram'
[Link]=23
[Link]()
name Ram
course Data Analyst
age 23
In [59]: # railway --> classes
class Railway():
fname='Vipul'
lname='Pandey'
dept='Delhi'
to='Goa'
def info(self):
print('Name\t',[Link]+' '+[Link])
print('dept\t',[Link])
print('to\t',[Link])
In [60]: obj1=Railway()
obj2=Railway()
[Link]()
Name Vipul Pandey
dept Delhi
to Goa
In [61]: [Link]='Anshu'
[Link]='Kumar'
[Link]='Dubai'
[Link]()
Name Anshu Kumar
dept Delhi
to Dubai
In [62]: #class
class Employee:
pass
In [63]: emp1=Employee()
[Link] = 'Gaurav'
[Link]='Data Analyst'
In [64]: [Link]
Out[64]: 'Gaurav'
In [65]: # init method --> constructors
class Employee:
amt=1.20
def __init__(self,fname,lname,desig='',sal=0):
[Link]=fname
[Link]=lname
[Link]=desig
[Link]=sal
[Link]=[Link]()+[Link]()+'@[Link]'
def info(self):
print('Name of Emp\t',[Link]+' '+[Link])
print('Designation \t',[Link])
print('Email \t\t',[Link])
print('Salary \t\t',[Link])
def apply_raise(self):
[Link]=[Link]*[Link]
print('Salary after appraisal\t',[Link])
In [66]: emp1 = Employee('Vipul','Pandey','Data Analyst',100000)
emp2=Employee(lname='Kumar',fname='Anshu')
In [67]: [Link]()
print('-'*60)
[Link]()
Name of Emp Vipul Pandey
Designation Data Analyst
Email vipulpandey@[Link]
Salary 100000
------------------------------------------------------------
Name of Emp Anshu Kumar
Designation
Email anshukumar@[Link]
Salary 0
In [68]: [Link]
Out[68]: 'vipulpandey@[Link]'
In [69]: [Link]()
Name of Emp Vipul Pandey
Designation Data Analyst
Email vipulpandey@[Link]
Salary 100000
In [70]: emp1.apply_raise()
Salary after appraisal 120000.0
In [71]: [Link]()
Name of Emp Vipul Pandey
Designation Data Analyst
Email vipulpandey@[Link]
Salary 120000.0
In [72]: from sklearn.linear_model import Lasso
In [73]: lr1=Lasso()
lr1
Out[73]: ▾ Lasso i ?
Lasso()
In [74]: lr2=Lasso(alpha=50,max_iter=100,tol=0.1)
lr2
Out[74]: ▾ Lasso i ?
Lasso(alpha=50, max_iter=100, tol=0.1)
In [ ]:
🧬Explanation
Inheritance in Python – Complete
Inheritance in Python is a fundamental concept in Object-Oriented Programming
(OOP) that allows one class (called the child class or derived class) to acquire
properties and behaviors (methods) from another class (called the parent class or
base class).
Why is inheritance useful?
• Code Reusability: Avoid rewriting common code.
• Hierarchy: Establish a relationship between classes.
• Extensibility: Add or override features in the child class.
🔹 Parent Class and Child Class
In inheritance, there are mainly two types of classes:
• Parent Class (Base Class)
The class whose properties and methods are inherited.
• Child Class (Derived Class)
The class that inherits properties and methods from another class.
The child class can:
• Use parent class methods
• Add new methods
• Modify existing behavior
🔹 Why Do We Need Inheritance?
Inheritance is used to:
• Avoid writing the same code again and again
• Reduce redundancy
• Improve readability
• Build a real-world relationship between classes
Example:
A Student class and a Teacher class can inherit from a common Person class.
In [1]: # init method --> constructors
class Employee:
amt=1.20
def __init__(self,fname,lname,desig='',sal=0):
[Link]=fname
[Link]=lname
[Link]=desig
[Link]=sal
[Link]=[Link]()+[Link]()+'@[Link]'
def info(self):
print('Name of Emp\t',[Link]+' '+[Link])
print('Designation \t',[Link])
print('Email \t\t',[Link])
print('Salary \t\t',[Link])
def apply_raise(self):
[Link]=[Link]*[Link]
print('Salary after appraisal\t',[Link])
In [2]: # plan of action
#employee--> child(Developer,Manager)
In [3]: #Method overiding
class Developer(Employee):
#pass
def __init__(self,fname,lname,desig,sal,lang):
super().__init__(fname,lname,desig,sal)
[Link]=lang
def info(self):
print('-'*60)
super().info()
print('Language\t',[Link])
print('-'*60)
In [4]: dev1=Developer(fname='Vipul',lname='Pandey',desig='Developer',sal=100000,lang='Python'
[Link]()
------------------------------------------------------------
Name of Emp Vipul Pandey
Designation Developer
Email vipulpandey@[Link]
Salary 100000
Language Python
------------------------------------------------------------
In [5]: #manager
class Manager(Employee):
def __init__(self,fname,lname,desig,sal,emp=None):
super().__init__(fname,lname,desig,sal)
[Link] = emp
if emp==None:
[Link]= []
else:
temp = None
temp = [Link]
[Link] = []
[Link](temp)
def add_emp(self,cand):
[Link](cand)
print(f'{cand} is successfully added to your list.')
def remove_emp(self,cand):
if cand not in [Link]:
print(f'{cand} : Candidate not found.')
else:
[Link](cand)
print(f'{cand} successfully removed.')
def replace_emp(self,cand,replacement):
if cand not in [Link]:
print('Candidate not found')
else:
temp = [Link](cand)
[Link][temp] = replacement
print(f'successfully replaced {cand} with {replacement}')
def show_all(self):
count =1
for i in [Link]:
print(count,'.',i)
count+=1
In [6]: man1=Manager('Vipul','Pandey','Manager',100000,'Ram')
In [7]: [Link]
Out[7]: ['Ram']
In [8]: man1.add_emp('Gaurav')
man1.add_emp('Raju')
man1.add_emp('Harsh')
Gaurav is successfully added to your list.
Raju is successfully added to your list.
Harsh is successfully added to your list.
In [9]: [Link]
Out[9]: ['Ram', 'Gaurav', 'Raju', 'Harsh']
In [10]: man1.remove_emp('soorya')
man1.remove_emp('Harsh')
soorya : Candidate not found.
Harsh successfully removed.
In [11]: [Link]
Out[11]: ['Ram', 'Gaurav', 'Raju']
In [12]: man1.replace_emp('Raju','Anshul')
successfully replaced Raju with Anshul
In [13]: [Link]
Out[13]: ['Ram', 'Gaurav', 'Anshul']
In [14]: man1.show_all()
1 . Ram
2 . Gaurav
3 . Anshul
Types of Inheritance in Python:
• Single Inheritance – One child inherits from one parent.
• Multiple Inheritance – One child inherits from multiple parents.
• Multilevel Inheritance – Child -> Parent -> Grandparent.
• Hierarchical Inheritance – Multiple children inherit from one parent.
• Hybrid Inheritance – Combination of the above.
🔹 Single Inheritance
Single inheritance occurs when:
• One child class inherits from one parent class
Features:
• Simple and easy to understand
• Improves code reuse
• Commonly used in beginner-level programs
Use case:
• A class extends basic functionality from one base class
🔹 Multiple Inheritance
Multiple inheritance occurs when:
• One child class inherits from more than one parent class
Features:
• Child class gets access to multiple class features
• Useful when combining different functionalities
• Must be handled carefully to avoid confusion
Important concept:
• Method Resolution Order (MRO) decides which method is called first
🔹 Multilevel Inheritance
Multilevel inheritance occurs when:
• A class inherits from a class that already inherits another class
Structure:
• Grandparent → Parent → Child
Features:
• Represents real-life hierarchy
• Each level adds more features
• Improves modularity
🔹 Hierarchical Inheritance
Hierarchical inheritance occurs when:
• Multiple child classes inherit from one parent class
Features:
• One base class shared by many subclasses
• Helps maintain common behavior
• Reduces duplication
Example use case:
• One base class for different types of users
🔹 Hybrid Inheritance
Hybrid inheritance is:
• A combination of two or more types of inheritance
Features:
• Complex structure
• Powerful but harder to manage
• Uses MRO to resolve conflicts
Used in advanced-level applications.
🔹 Method Overriding
Method overriding happens when:
• A child class defines a method with the same name as the parent class
Purpose:
• To change or extend parent class behavior
• Allows customization in child class
This supports runtime polymorphism.
🔹 Use of super()
The super() concept is used to:
• Access parent class methods and attributes
• Avoid code duplication
• Maintain proper inheritance flow
It ensures that parent class functionality is not lost.
🔹 Constructor in Inheritance
Constructors can also be inherited.
• Parent class constructor can be accessed
• Child class can have its own constructor
• Both can work together using proper calling
This helps in initializing data properly.
🔹 Method Resolution Order (MRO)
MRO defines:
• The order in which Python searches for methods in multiple inheritance
Important points:
• Python follows C3 linearization
• MRO avoids ambiguity
• Can be checked to understand execution flow
🔹 Advantages of Inheritance
• Code reuse
• Easy maintenance
• Logical class structure
• Faster development
• Better scalability
🔹 Disadvantages of Inheritance
• Increases complexity
• Tight coupling between classes
• Difficult debugging in deep inheritance
Use inheritance only when there is a clear relationship.
🔹 Real-World Use Cases
Inheritance is used in:
• Banking systems
• Employee management systems
• Game development
• Data science class structures
• Framework and library design
In [15]: # single inheritance
class parent:
print('parent')
class child(parent):
pass
parent
In [16]: # multiple inheritance
class papa:
pass
class mummy:
pass
class child(papa,mummy):
pass
# help(child)
In [17]: # mutlilevel inheritance
class grandparents:
pass
class parents(grandparents):
pass
class child(parents):
pass
In [18]: # Hierarchical Inheritance
class parent:
pass
class child1(parent):
pass
class child2(parent):
pass
✅ Final Summary
Inheritance is a core pillar of Object-Oriented Programming.
It helps build structured, reusable, and maintainable code.
Understanding inheritance is essential for writing professional and scalable
Python applications.
In [ ]: