Python Fundamentals (Part4)
ayushsharma553513@[Link]
Concepts : Object Oriented Programming in Python
Object Oriented Programming
Let’s suppose we need to build a software to store all the information related to
students studying in our college.
These students could have a lot of properties (like name, parent’s name, address,
graduation year, cgpa etc.) associated with them.
They could also have a lot of behaviours (like fee payment, scholarship calculation,
checking minimum attendance criteria etc.) associated with them.
Without existing Python data types, we can choose to store this information in lists or
dictionaries but that would not be efficient. As we have a lot of properties, we’d have
to create too many lists and it’ll be hard to keep track of them. If we use dictionaries,
we’d have to re-define the same keys again & again & we won’t logically be able to
associate behaviours with that data.
So to simplify our work of creating such a software we have Object Oriented
Programming - which gives us the concept of classes & objects.
What is a Object Oriented Programming (OOP)?
Object-oriented programming (OOP) in Python is a programming paradigm centered
around organizing code into objects: bundles of data (attributes) and behaviour
(methods). It helps us structure programs in a way that is modular, reusable, and
easier to maintain.
Note - It’s not compulsory to always use OOP concepts but they definitely help in a
lot of cases.
OOP models software as a collection of interacting objects, similar to how we think
about real-world entities. Each object represents something meaningful in our
program - such as a user, a car, a bank account, or an enemy in a video game.
In Python, OOP is based around classes, which are blueprints for creating objects.
What are Classes & Objects?
Class
A class is a blueprint or template for creating objects. We can think of a class as a
recipe: it describes what an object will look like (its attributes) and what it can do (its
methods), but it is not the object itself.
1
class Car:
brand = "Toyota"
ayushsharma553513@[Link]
Object
An object (or instance) is a realization of a class, it is the actual thing created based
on the class blueprint. Now based on the template we can create as many objects as
we want.
car1 = Car()
car2 = Car()
print([Link]) # Toyota
print([Link]) # Toyota
We use the “.” (Dot Operator) to access properties & methods of objects.
Class vs. Object
Class Object
Class is a blueprint/ template. An object is a concrete instance of a class.
Does not exist in memory until
Contains actual data & occupies memory.
instantiated.
One class can create any number of
Each object is independent.
objects.
Attributes & Methods
Attributes are variables and Methods are functions defined inside a class.
(We’ll cover both in detail)
Constructor in OOP
In Python, a constructor is a special method used to initialize newly created objects.
It is not responsible for creating the object, instead the constructor sets up the object
with initial values.
We use the init (self, ...) method to define our constructor. Whenever we
create an object of a class, Python automatically calls the init () method.
class Student:
def init (self):
print("constructor was called")
stu1 = Student() # "constructor was called"
2
self is a special parameter which refers to the instance of the class that is calling
the method. We don’t need to pass it explicitly.
ayushsharma553513@[Link]
We can also use constructor to initialize values for objects:
class Student:
def init (self, name):
[Link] = name
stu1 = Student("Rahul")
stu2 = Student("Harshita")
print([Link], [Link]) # Rahul Harshita
Types of Constructors
1. Default Constructors - A constructor with no parameters except self .
2. Parameterized Constructors - Takes parameters to initialize values uniquely for
each object.
Note - Python doesn’t support constructor overloading directly (like
Java/C++) i.e. having multiple constructors in the same class. Whichever
is written last is executed.
Attributes in OOP
Attributes are variables that belong to a class or an object. They store data/state of
the object.
Types of Attributes
1. Class Attributes
• Belong to the class itself, shared by all objects.
• Defined outside any method in the class.
class Student:
college = "ABC college" # class attribute
stu1 = Student ()
print([Link])
print([Link]) # class attribute can also be accessed with class name
3
2. Instance Attributes
• Belong individually to each object.
ayushsharma553513@[Link]
• Defined inside the init method using self .
• Each object gets its own copy.
class Student:
def init (self, name, gpa): # instance attributes
[Link] = name
[Link] = gpa
stu1 = Student("Rahul", 8.7)
print(stu1. name, [Link])
Methods in OOP
Methods are functions defined inside a class, representing the behaviour or
actions of an object.
Types of Methods
1. Instance Methods
• Take self as the first argument.
• Can access both instance attributes and class attributes.
class Student:
def init (self, name, marks):
[Link] = name
self. marks = marks
def display(self): # Instance method
print(f"Name: {[Link]}, Marks: {[Link]}")
2. Class Methods
• Use @classmethod decorator.
• Take cls (class) as first argument.
• Used to work with class-level data.
class Student:
school_name = "ABC School"
@classmethod
def change_school(cls, new_name):
cls.school_name = new_name
4
3. Static Methods
• Use @staticmethod decorator.
ayushsharma553513@[Link]
• Do not take self or cls .
• Behave like normal functions but belong to the class for logical grouping.
class Math:
@staticmethod
def add(a, b):
return a + b
OOP Pillars
Let’s understand the 4 Key pillars of OOP - Encapsulation, Abstraction, Inheritance &
Polymorphism.
Encapsulation
Encapsulation is the bundling of data (variables) and methods (functions) that
operate on that data into a single unit (a class), along with controlling access to that
data. This is done to protect the data from accidental or unauthorized modification.
To implement encapsulation, we use access modifiers. Python has 3 access levels:
1. Public members
• Accessible everywhere, written like normal variables.
class Student:
def init (self, name):
[Link] = name # public variable
s = Student("Rahul")
print([Link]) # Allowed
2. Protected members
• Indicated by a single underscore _ (suggest - “Don’t access directly unless
needed.”)
• Still accessible from outside (not truly protected).
• Intended for internal use or inheritance.
5
class Person:
def init (self):
ayushsharma553513@[Link]
self._age = 20 # protected variable
p = Person()
print(p._age) # Technically allowed, but not recommended
3. Private members
• Indicated by a double underscore
• Python does name mangling: the variable name becomes _ClassName variable .
• Cannot be accessed directly from outside.
class Bank:
def init (self, balance):
self. balance = balance # private variable
b = Bank(5000)
print(b. balance) # ERROR: attribute not accessible
To access:
print(b._Bank balance) # Allowed (name-mangled form)
Python uses naming conventions with access modifiers, not strict
enforcement (like Java/C++).
Getters & Setters
When we make a variable private, we use methods to read it (getters) or update it
(setters).
class Employee:
def init (self, salary):
self. salary = salary # private
def get_salary(self): # getter
return self. salary
def set_salary(self, new_salary): # setter
self. salary = new_salary
e = Employee(50000)
print(e.get_salary())
e.set_salary(60000)
6
Inheritance
Inheritance is where one class (child) acquires the properties and behaviors (variables
ayushsharma553513@[Link]
+ methods) of another class (parent).
The class whose properties are inherited - Parent / Base / Superclass
The class that inherits - Child / Derived / Subclass
class Employee: # parent class
start_time = "9AM"
end_time = "5PM"
class Teacher(Employee): # child class
def init (self, subject):
[Link] = subject
t1 = Teacher("Data Science")
print([Link], t1.start_time, t1.end_time)
Inheritance enables:
• Code reuse
• Extensibility
• Cleaner, maintainable design
• Polymorphism
Types of Inheritance
1. Single Inheritance
A child inherits from one parent.
# Parent → Child
class Parent:
def display(self):
print("Parent class")
class Child(Parent):
pass
c = Child()
[Link]() # Output: Parent class
7
2. Multi-level Inheritance
A child inherits from a parent, and another class inherits from the child.
ayushsharma553513@[Link]
# Grandparent(Employee) → Parent(AdminStaff) → Child(Accountant)
class Employee:
start_time = "9AM"
end_time = "5PM"
class AdminStaff(Employee):
def init (self, role):
[Link] = role
class Accountant(AdminStaff):
def init (self, salary, role):
super(). init (role)
[Link] = salary
acc1 = Accountant(50_000, "CA")
print([Link], [Link], acc1.start_time, acc1.end_time)
3. Multiple Inheritance
A child inherits from more than one parent class.
class Teacher:
def init (self, salary):
[Link] = salary
class Student():
def init (self, gpa):
[Link] = gpa
class TA(Teacher, Student):
def init (self, name, salary, gpa):
super(). init (salary) # call parent constructor
Student. init (self, gpa) # call parent constructor
[Link] = name
ta = TA("Rahul", 50_000, 7.5)
print([Link], [Link], [Link])
super() keyword - Used to call parent class’s method from child class.
Abstraction
Abstraction is hiding unnecessary implementation details and showing only the
essential features to the user.
8
Example - In real life when we drive a car & press the breaks, the car stops. But we
don’t need to know how the hydraulic systems work. To implement same idea in
Python, we have abstraction.
ayushsharma553513@[Link]
We implement abstraction with abstract classes & abstract methods.
Abstract Class
An abstract class in Python is one which:
• Cannot be instantiated
• Can contain normal + abstract methods
• Usually acts as a blueprint for child classes
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
Abstract Method
It is a method declared but not implemented (Children must override abstract methods).
@abstractmethod
def method_name(self):
Example of Abstraction
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound():
pass
class Lion(Animal):
def make_sound(self):
print("Roar!")
class Cow(Animal):
def make_sound(self):
print("Moo!")
lion = Lion()
lion.make_sound()
cow = Cow()
cow.make_sound()
9
Polymorphism
Polymorphism is the ability of a single function, operator, or object to behave
ayushsharma553513@[Link]
differently based on the context. (“poly” = many, “morph” = forms)
The idea is that:
• Same method name - works differently for different objects
• Same operator - behaves differently depending on operand types
Let’s look at an example:
print(1 + 2) # adds 2 numbers
print("1" + "2") # concatenates 2 strings
Same ‘+’ operator being used for 2 different operations, called Operator Overloading.
Let’s look at two popular types of polymorphism:
1. Function Overriding (or Method Overriding)
• When a child class provides its own version of a method that already exists in
the parent class (Both methods should have same name)
• Type of Runtime Polymorphism (dynamic binding)
• Child method takes precedence over parent method.
class Animal:
def sound(self):
print("Some generic sound")
class Dog(Animal):
def sound(self):
print("Bark")
a = Animal()
dog = Dog()
[Link]() # Some generic sound
[Link]() # Bark
10
2. Duck Typing
• Works on the idea: “If it looks like a duck and quacks like a duck, it must be a
ayushsharma553513@[Link]
duck.”
class Dog:
def speak(self):
print("Bark")
class Cat:
def speak(self):
print("Meow")
class Robot:
def speak(self):
print("Beep Boop")
def make_it_speak(entity):
[Link]() # doesn’t care about type
d = Dog()
c = Cat()
r = Robot()
for e in [d, c, r]:
make_it_speak(e)
| Keep Learning & Keep Exploring!
11