Python Module - 4 - OOPs Notes (21EC643)
Python Module - 4 - OOPs Notes (21EC643)
Module-4
Introduction
• There are two main types of programming: procedural(structured) and Object-oriented.
• Procedural programming is about writing procedures or functions that perform operations
on the data, while object-oriented programming is about creating objects that contain both
data and functions. Object-oriented programming uses user defined types to organize both
code and data.
• Python is an object-oriented programming language, and class is a basis for any object-
oriented programming language.
Explanation :
Line 1-4: Creating class
Create a class named ClassName.
The __init__ method is a constructor used to initialize the attributes of the object.
The 'self' parameter represents the instance of the class and is used to access its attributes and
methods.
Example 1: Class & Methods (Here methods are defined inside the class)
class Solve:
def __init__(self, a,b):
self.a=a
self.b=b
def add(self):
y1 = self.a + self.b
return (y1)
def mul(self,c):
y2 = self.a *self.b* c
return y2
a=3;
b=5;
c=8
obj = Solve(a,b) # Creation of object
y = obj.add()
z = obj.mul(c)
Here add function is defined is within the class. So it is accessed using the dot operator
Note : The number of variables passed to the __init__ function and the number of variables passed
during object creation should match. In this example, a and b are passed during object creation to match
the parameters a and b defined in the __init__ function.
Explanation:
1. Class Initialization (constructor (__init__)):
o Constructor (__init__) takes two parameters (a and b) and initializes the object's
attributes self.a and self.b
o Whenever an object of the Solve class is created, the constructor initializes the object's
attributes with the provided values.
2. Methods:
o The add method does not take any parameters other than self. It adds the object's
attributes self.a and self.b and returns the result.
o The mul method takes an additional parameter (c) besides self. It multiplies the object's
attributes self.a and self.b with c and returns the result.
3. Object Creation:
o An object obj of the Solve class is created with the variables a and b.
4. Method Call:
o Methods are called on object using dot (.) operator.
o Add method is called on the obj object, and the result is stored in the variable y.
o The mul method is called on the obj object with the variable c, and the result is stored in
the variable z.
5. Output:
o The results are printed using formatted strings, displaying the sum of the two numbers and
the product of the three numbers.
Note:
• The number of variables passed to the __init__ function and the number of variables passed
during object creation should match. In this example, a and b are passed during object creation to
match the parameters a and b defined in the __init__ function.
a = 5
b = 10
y = obj.add(a, b)
z = obj.mul(a, b)
If init is not used, we have to the pass the variables to functions not, while creating the object.
Explanation: Write the explanation in your own words
Another Example
#To create the class (without init)
class student:
name="Virat"
sem=6
college="SGBIT"
Here name, sem, college are defined within the class, so they are
accessed using dot operator
Here add function is defined is outside the class. So it is called directly with out using the dot
operator
#Cetaing class
class Solve:
def __init__(self, a, b): #init constructor
self.a=a
self.b=b
def add(self):
y1 = self.a + self.b
return (y1)
def mul(self,c):
y2 = self.a *self.b* c
return y2
a=3;
b=5;
c=8
#creation of object
obj = Solve(a,b)
y = obj.add()
z = obj.mul(c)
Explanation:
Creation of Class
Class Solve is created using keyword class
Method Call:
o Methods are called on object using dot (.) operator.
o Add method is called on the obj object, and the result is stored in the variable y.
o The mul method is called on the obj object with the variable c, and the result is stored in the
variable z.
Output:
• The results are printed using formatted strings, displaying the sum of the two numbers and the
product of the three numbers.
Note:
• The number of variables passed to the __init__ function and the number of variables passed
during object creation should match. In this example, a and b are passed during object creation to
match the parameters a and b defined in the __init__ function.
Explain Attributes
• Variables associated with either object or class are called attributes
Example:
class Solve:
#class variables (inside the class)
class_var_a=50;
class_var_b=60;
def add(self):
y1 = self.a +self.b
return y1
#regular variables
a=2;
b=5;
z1= obj.add(a, b)
z2 = obj.add(obj.a, obj.b)
z3= obj.add(class_var_a, class_var_b)
obj.a =10.0
obj.b =20.0
Object diagram
• A state diagram of object and its attributes is called as object diagram.
Solve
a 10.0
obj
b 20.0
print(obj.b)
Output: 20.0
Write python program to find the area and perimeter of rectangle using oops
class Rectangle:
def __init__(self, height, width):
self. height = height
self. width = width
def area(self):
y1= self.height * self.width
return (y1)
def perimeter(self):
y2=(self.height + self.width)*2
return (y2)
Write a class Point representing a point on coordinate system. Implement following functions
• A function read_point() to receive x and y attributes of a Point object as user input.
• A function distance () which takes two objects of Point class as arguments and computes
the Euclidean distance between them.
• A function print_point() to display one point in the form of ordered-pair.
Program:
import math
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def read_point(self):
self.x = float(input("Enter the x-coordinate: "))
self.y = float(input("Enter the y-coordinate: "))
return (self.x, self.y)
Output:
class Point:
pass
def print_point(p):
print(" {p.x}, {p.y}”)
#Create 2 objects
p1=Point()
p2=Point()
# Calling the functions (since these are outside class, no need to call
using objects, directly pass the object.
Z1=read_point(p1)
Z2=read_point(p2)
Write a class Rectangle containing numeric attributes width and height. This class should contain
another attribute corner which is an instance of another class Point.
Implement following functions
▪ A function find_center() to compute centre point of the rectangle
▪ A function resize() to modify the size of rectangle
▪ A function to print corner point as an ordered-pair
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def print_point(self):
print(f"({self.x}, {self.y})")
class Rectangle:
def __init__(self, width, height, corner_point):
self.width = width
self.height = height
self.corner = corner_point #corner is object of point class
def find_center(self):
center_x = self.corner.x + self.width / 2
center_y = self.corner.y + self.height / 2
return Point (center_x, center_y)
def print_corner(self):
self.corner.print_point()
center = rect.find_center()
print(f"The center of the rectangle is: {center.x}, {center.y}”)
def print_point(self):
print(f"({self.x}, {self.y})")
class Rectangle:
def __init__(self, width, height, corner_x, corner_y):
self.width = width
self.height = height
self.corner = Point(corner_x, corner_y) # corner is an object of Point class
def find_center(self):
center_x = self.corner.x + self.width / 2
center_y = self.corner.y + self.height / 2
center_point= Point(center_x, center_y)
return center_point
def print_corner(self):
self.corner.print_point()
center = rect.find_center()
print(f"The center of the rectangle is: {center.x}, {center.y}")
class Point:
''' Blank class'''
resize(box,50,70)
print("Rectangle after resize:")
print("width=%g, height=%g"%(box.width, box.height))
center=find_center(box)
print("The center of resized rectangle is:")
print_point(center)
Here, this function takes an object self (object of rectangle) as an argument. And this function
returns the object of class point.
• Input:
• It takes the self parameter, which refers to the current instance of the Rectangle class.
This means it operates on the specific rectangle object that calls this method.
rect.width = rect.width + 50
rect.height = rect.height + 100
Here, rect is an instance of the Rectangle class. By adding 50 to rect.width and 100 to rect.height, we
changed its dimensions. This shows mutability because the original attributes (width and height) are
modified directly.
Example 2:
def resize(self, w, h):
self.width += w
self.height += h
return [self.width, self.height]
The values w and h are added to width and height. Hence the size of rectangle is modified. This
shows that objects are mutable.
o Both list1 and list2 point to the same list [1, 2, 3] in memory. They are aliases of each other.
o Effect: Changes made in one alias, affects other object. Because both have same memory
Example:
list2.append(4)
print(list1)
print(list2)
# Output: list1= [1, 2, 3, 4]
list2=[1, 2, 3, 4]
______________________________________________________________________
Copying
o Copying creates a new object with the same value as the original, independent of the original
object. Here both copied and original will have different memory locations
o To copy, we have to use inbuilt method .copy() from library copy
o There are 2 types of Copy
1. Shallow copy
2. Deep copy
Shallow copy:
The operation in which copying the contents of objects as well as copying the references to
embedded object is called shallow copy. This type of copy operation is performed using copy
function in copy module ( copy.copy())
Example 1
import copy
Example 2
import copy
Explanation:
• Only the top-level elements (like integers or strings) of object are duplicated. It does not
duplicate nested objects; but it only copies references of nested objects, but the NOT actual
elements of nested object.
• Impact: Changes made to the nested objects in the shallow copy can affect the original
object.
• In example 1: the value 50 is appeneded to list2, but does not affect the list1 (ie it is not
appended to list1)
• In example 2: It is case of nested object. When we appended the 50 in the nested object of
list2, even list1 got affected and value 50 also got added to list1
2. Deep copy
o The operation in which copying the contents of objects as well as copying the embedded
objects is called deep copy. This type of copy operation is performed using deepcopy
function in copy module (copy.deepcopy())
Explanation:
• Here all elements of object, including nested object are duplicated. The copy and original
objects are fully independent to each other
• Impact: Changes made to the nested objects in the deep copy can NOT affect the original
object.
Time ( define a class called Time that records the time of day)
Example: To write python program to define a class called Time that records the time of day.
class Time:
def __init__(self, hour=0, minute=0, second=0):
self.hour = hour
self.minute = minute
self.second = second
def display(self):
print(f'{self.hour:02}:{self.minute:02}:{self.second:02}')
Function
There are two types of functions
o pure functions
o modifiers.
def display_time(self):
print(f'{self.hour:02d}:{self.minute:02d}:{self.second:02d}')
• We have created the class Time. Then we have defined 2 functions add_time and disp_time
• Here, the function add_time() takes two arguments of type Time, and returns a Time object,
whereas, it is not modifying contents of t1 and t2. Such functions are called as pure functions
def display_time(self):
print(f'{self.hour:02d}:{self.minute:02d}:{self.second:02d}')
self.minute += 1
• For example, if we consider the problem of adding two-time objects. This problem involves
the numbers with base 60 (as every hour is 60 minutes and every minute is 60 seconds), proper
planning before coding makes the things easier.
# Class definition
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
def perimeter(self):
return 2 * (self.height + self.width)
# Displaying results
print('The area of rectangle using function:', y)
print('The Perimeter of rectangle using method:', z)
Example:
class Rectangle:
def __init__(self, height, width):
self. height = height
self. width = width
def area(self):
return self.height * self.width
def perimeter(self):
return (self.height + self.width)*2
def __str__(self):
return "My name is %s and Roll no is %d" %(self.name,self.roll_no)
Output:
Operator Overloading
• Operator overloading refers to the ability of a built-in operator to behave differently
according to the different operands.
• It is a case of polymorphism, where operators have different implementations based on
operands or parameters
• For example, the operator ‘+’ is used to:
o Add two integers.
Operator overloading: To perform the operator overloading, python provides some special
function or magic function which automatically gets invoked, when associated with that particular
operator. The method should begin and end with a double underscore (__).
For example, To overload the '+' operator, we will use the __add__ special method.
Program to overload the ‘+’, ‘-‘, ‘*’, operators
class A:
def __init__(self, x):
self.x = x
Output:
30
-10
200
Polymorphism
• Poly = many and morphism= forms; Polymorphism means having multiple forms.
• Polymorphism means object or method exhibits different behaviour in different contexts.
Function having the same name behaves differently in different situations
• Polymorphism in operators: The + operator can be used to add the 2 integers and also it can
be used to concatenate the 2 lists or tuples.
Example1:
a = 23
b = 11
print(a+b) #addition of 2 integers
Output: 23
s1 = "Hello"
s2 = "Dhoni"
print(s1+ s2) #concatenation of string
Output: Hello Dhoni
• Polymorphism in in-built functions:
In case of len () function, if the input is string, it counts every letter in it. But if the input is
tuple or a dictionary, it processes them differently.
• Polymorphism in user-defined methods:
We can create methods with same name in different classes. Here the function with same
name called area is in 2 different classes. The function area behaves as per the context
Example:
class Rectangle:
def __init__(self, length, breadth):
self.l = length
self.b = breadth
def area(self):
return self.l * self.b
class Circle:
def __init__(self, radius):
self.r = radius
def area(self):
return pi * self.r ** 2
Another Example:
User defined function: Histogram
Histogram function to count the number of times each letter appears in a word
s='dhonii'
def histogram(s):
d = dict()
for i in s:
if i not in d:
d[i] = 1
else:
d[i] += 1
return d
• This function also works for lists, tuples, and even dictionaries.
• Functions which work with several types are called polymorphic.
Inheritance
def add(self):
y = self.a + self.b
return y
#Child class
# Child class inheriting from the Solve class
class Child_Solve(Parent_Solve):
def multiply(self):
z = self.a * self.b
return z
# call the add method from the parent class using child object
#It means child class have all the methods and variables of parent
class
Result1 = obj.add()
print("Sum:", sum_result)