0% found this document useful (0 votes)
2 views20 pages

Module 5

Uploaded by

druthi.shetty77
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views20 pages

Module 5

Uploaded by

druthi.shetty77
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Module 5

Object-oriented programming: A powerful style of programming in which data and the operations
that manipulate it are organized into objects.
Object-oriented language: A language that provides features, such as user-defined classes and
inheritance, that facilitate object-oriented programming.

Objects are Mutable


In Python, objects are mutable if their internal state (attributes) can be changed after creation.
A Rectangle object has attributes like:
 position (corner.x, corner.y)
 size (width, height)
We can change these values without creating a new object.

In Python, objects of user-defined classes are mutable by default.


 This means once an object is created, we can modify its attributes without
creating a new object.
 When we change an attribute, the change is reflected in the same object
memory location.
Examples of mutable objects:
 Class objects
 Lists
 Dictionaries
Examples of immutable objects:
 Integers
 Strings
 Tuples

1
Example
class Employee:
def __init__(self, name, salary):
[Link] = name
[Link] = salary
e1 = Employee("Anil", 25000)
[Link] = 30000
print([Link]) print([Link])

Explanation
 e1 is an object of class Employee
 Salary value is changed after object creation
 The same object is updated → object is mutable

Why mutability is important


 Allows updating object properties
 Useful for real-world modeling (moving, resizing, updating)
 Avoids creating new objects repeatedly
 Makes programs efficient and flexible

Sameness
Sameness refers to whether two variables refer to the same object in memory.
Python provides the is operator to check identity
 is → checks same object
 == → checks same value 👉
Two variables can:
 Refer to the same object
 Refer to different objects with same values

2
The word “same” can have two different meanings, both in real life and in programming.
In Object-Oriented Programming, this idea is called object sameness or equality.

Two meanings of “same”


1. Same data, different objects
 Like Alice and Bob having the same car model
 Objects look the same but are separate
2. Same object (same identity)
 Like Alice and Bob having the same mother
 Only one object, referred to by two names

Ex:
class Laptop:
def __init__(self, brand):
[Link] = brand
l1 = Laptop("HP")
l2 = l1 # same object
l3 = Laptop("HP") # different object
print(l1 is l2)
print(l1 is l3)
print([Link] == [Link])

Output:
True
False
True
Explanation
 l1 and l2 refer to the same memory object
 l3 is a separate object, though value is same
3
Copying Objects
 Copying is the process of creating a new object with the same content as an existing object.
 Copying helps avoid unexpected changes caused by aliasing.

When copying objects, we must ensure:


Whether the new object shares internal data Or has completely independent data Python supports:
1. Shallow Copy
2. Deep Copy

Shallow Copy
A shallow copy creates a new object, but it does not copy embedded objects.
Instead, it copies references to them.
Ex:
import copy
p1 = Point(3, 4)
p2 = [Link](p1)
print(p1 is p2) # False
print(same_coordinates(p1, p2)) # True

Output
[70, 80, 90, 100]
[70, 80, 90, 100]

Explanation
 r1 and r2 are different objects
 But both share the same list
 Change in one affects the other

4
Deep Copy
A deep copy creates:
 a new object
 new copies of all embedded objects
Example
import copy
r1 = Result([70, 80, 90]) r2 = [Link](r1)
[Link](100)
print([Link]) print([Link])
Output
[70, 80, 90]
[70, 80, 90, 100]
Explanation
 Both objects and internal data are independent
 Changes do not affect the original object

5
Inheritance: Pure functions, Modifiers, Generalization, Operator Overloading,
Polymorphism

Pure Functions :
A pure function is a function that:
1. Always produces the same output for the same input
2. Does not modify external state (no side effects)
Pure functions do not depend on global variables
 They do not change object attributes, files, or external data
 They are predictable, reusable, and easy to test
 Widely used in functional programming and safe OOP design

Example: add_time as a Pure Function


def add_time(t1, t2):
h = [Link] + [Link]
m = [Link] + [Link]
s = [Link] + [Link]
sum_t = MyTime(h, m, s)
return sum_t
Why this is a pure function?
 t1 and t2 are not changed
 A new MyTime object is created
 No side effects (no print, no input, no global changes)
Impure Function Example:

total = 0
def add_value(x):
global total total += x
This is not pure because it modifies a global variable.

6
Modifiers
A modifier is a function or method that changes (modifies) the object passed to it as a parameter.
Unlike a pure function, a modifier does not create a new object—it updates the existing object
directly.
Modifiers are functions or methods that change the state of an object.
 They modify object attributes
 Changes are visible to the caller
 They work on objects, not on visibility

Example: add_time as a Pure Function


def add_time(t1, t2):
h = [Link] + [Link]
m = [Link] + [Link]
s = [Link] + [Link]
sum_t = MyTime(h, m, s)
return sum_t

This is a pure function


 t1 and t2 are not changed
 A new MyTime object is created
 No side effects (no print, no input, no global changes)

Using the Pure Function


current_time = MyTime(9, 14, 30)
bread_time = MyTime(3, 35, 0)
done_time = add_time(current_time, bread_time)
print(done_time)
Output
12:49:30

7
Difference between Pure Function and Modifier Function in Python

Modifier
Aspect Pure Function
Function

A function that A function


does not change that modifies
Definition
the objects the state of an
passed to it object

Original object Original


Effect on
remains object is
object
unchanged changed

Creates and Does not


Object
returns a new create a new
creation
object object

Has side
Side effects No side effects
effects

Usually returns Usually


Return value
a new object returns None

Object state
Object state
remains the
Object state changes after
same after
function call
function call

Less safe,
Safer and may affect
Safety
predictable other
references

Reusability Highly reusable Less reusable

Calculations, Updating
Example use
transformations object values

Object-
Functional
Programming oriented
programming
style programming
style
style

8
Generalization
Generalization means solving a problem in a more abstract and general way instead of handling
many special cases separately.
In programming, generalization often makes code:
simpler
more reliable
easier to extend
—even though it may seem harder at first.

Generalization using Time Example


When working with time (hours : minutes : seconds), a naive approach is:
 Add seconds
 Handle carry to minutes
 Handle carry to hours
 Deal with borrowing for subtraction
This leads to:
❌ many special cases
❌ long and error-prone code

Generalized Approach (Base Conversion Idea)


Time can be treated as a base-60 number:
 60 seconds = 1 minute
 60 minutes = 1 hour
Steps:
1. Convert time → total seconds (base-10)
2. Perform arithmetic (+ or −)
3. Convert back → hours, minutes, seconds
This is generalization.
Naive (Specialized) Generalized

Many if/while checks Simple arithmetic

Hard to debug Easy to debug Why Generalization is Better


9
Error-prone Reliable

Hard to extend Easy to extend


Overloading + Operator (__add__)
Example: MyTime class
class MyTime:
def __init__(self, h, m, s):
[Link] = h
[Link] = m
[Link] = s
def to_seconds(self):
return [Link]*3600 + [Link]*60 + [Link]
def __add__(self, other):
return MyTime(0, 0, self.to_seconds() + other.to_seconds())
def __str__(self):
total = self.to_seconds()
h = total // 3600
m = (total % 3600) // 60
s = total % 60
return f"{h:02}:{m:02}:{s:02}"
Usage
t1 = MyTime(1, 15, 42)
t2 = MyTime(3, 50, 30)
t3 = t1 + t2
print(t3)

Output
05:06:12

t1 + t2 is internally:

10
Overloading + for Point
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
p1 = Point(3, 4)
p2 = Point(5, 7)
print((p1 + p2).x, (p1 + p2).y) # 8 11

Polymorphism
Polymorphism means the same function or operation can work with objects of different types, as long
as those objects support the required operations.
The word polymorphism means “many forms.”

What is Polymorphism?
Polymorphism allows a single function or operation to behave differently depending on the type of
object passed to it.
 One function
 Multiple data types
 Same operation, different behaviour
Polymorphic Function multadd
def multadd(x, y, z):
return x * y + z
This function works for any types where:
 x * y is valid
 (x * y) + z is valid

11
Using Numbers
multadd(3, 2, 1)
Output: 7

Polymorphism allows a single function or operation to behave differently depending on the type of
object passed to it.
 One function
 Multiple data types
 Same operation, different behavior

Why Polymorphism is Needed


Normally, methods work on specific types.
But many operations (like +, *, print) are common across types.
Polymorphism allows us to:
write generic functions
reduce code duplication
make programs flexible and reusable

Function multadd
def multadd(x, y, z):
return x * y + z
This function works for any types where:
 x * y is valid
 (x * y) + z is valid

Using Numbers
multadd(3, 2, 1)
✔ Output: 7

12
Duck Typing (Key Rule in Python)
Python follows duck typing:
“If it looks like a duck and quacks like a duck, it is a duck.”
Meaning:
If an object supports all the operations used inside a function, then the function can work with that
object.
Python does not care about the object’s class — only about its behavior.

🔹 Example: front_and_back Function


def front_and_back(front):
import copy
back = [Link](front)
[Link]()
print(str(front) + str(back))
Operations used:
 copy
 reverse
 str

Exceptions: Catching Exceptions, Raising your own exceptions

Exceptions
An exception is a runtime error that occurs while a program is executing.

When an exception happens:


 Python stops the program
 It prints a traceback
 The last line shows:
o Type of error
o Error message

13
Examples of Exceptions

1. Division by zero
print(55 / 0)
Exception:
ZeroDivisionError: division by zero

2. Accessing invalid list index


a = []
print(a[5])
Exception:
IndexError: list index out of range

3. Modifying a tuple
tup = ("a", "b", "d", "d")
tup[2] = "c"
Exception:
TypeError: 'tuple' object does not support item assignment

Why Do We Catch Exceptions?


Sometimes an error may happen, but we don’t want the program to crash.
Instead, we want to:
 Handle the error
 Show a friendly message
 Continue execution
This is done using try and except

Ex:
filename = input("Enter a file name: ")
try:
f = open(filename, "r")
except FileNotFoundError:
print("There is no file named", filename)

 try: Code that may cause an error


 except: Runs only if that error occurs
If the file does not exist → program does not crash

14
Structure of try Statement
A try statement can have four parts:
try:
# risky code
except ExceptionType:
# runs if exception occurs
else:
# runs if NO exception occurs
finally:
# always runs
Only try is mandatory
except, else, finally are optional

Raising Our Own Exceptions in Python


Can a program create its own exception?
Yes.

If a program detects an error condition, it can deliberately raise an exception using the raise keyword.
This is useful when:
 Input is invalid
 A rule is violated
 You want to stop execution and report a meaningful error
Example: Validating User Input (Age)
def get_age():
age = int(input("Please enter your age: "))
if age < 0:
my_error = ValueError("{0} is not a valid age".format(age))
raise my_error
return age

15
Explanation
age = int(input(...))
Takes age from the user
 if age < 0:
Checks for invalid input
 ValueError("{0} is not a valid age".format(age))
Creates an exception object with a custom message
 raise my_error
Raises the exception and stops normal execution
 return age
Runs only if no exception occurs

When raise is executed:


1. The function immediately stops
2. The exception is returned to the calling function
3. Python searches for a matching try–except
4. If found → exception is handled
5. If not found → Python prints a traceback and exits
This process is called: Unwinding the Call Stack
Example: call chain:
A → B → C → D → get_age()
If get_age() raises an exception:
 get_age() exits
 Control returns to D
 Then to C, B, A
 Until a try–except handles it

Program Output Example


Valid Input
Please enter your age: 42

16
Please enter your age: -2
Traceback (most recent call last):
ValueError: -2 is not a valid age
Error message shows:

Exception type (ValueError)


Custom message (-2 is not a valid age)

Built-in Exceptions
Python provides many built-in exceptions like:
 ValueError
 TypeError
 IndexError
 FileNotFoundError
Use the exception type that best matches the error

Raise Statement:
The raise statement is used to deliberately trigger an exception in a program.
User-Defined Exception:
An exception raised by the programmer to signal an error condition.
Unwinding the Call Stack:
The process of passing an exception back through calling functions until it is handled.

17
Inheritance in Object-Oriented Programming
Inheritance is one of the most important features of Object-Oriented Programming.
It allows us to create a new class from an existing class.
 The existing class is called the Parent class (or Base class)
 The new class is called the Child class (or Subclass)
The child class automatically gets all the methods and attributes of the parent class.

Why is it called Inheritance?


Just like a child inherits qualities from parents,
a child class inherits properties and methods from its parent class.

Main Advantages of Inheritance


1. Code Reusability
 We can reuse existing code
 No need to rewrite common methods
2. Easy Extension
 New methods can be added to the child class
 Parent class code remains unchanged
3. Better Program Structure
 Represents real-world relationships
 Makes the program easier to understand
4. Less Code, More Functionality
 Complex programs can be written in a simple and concise way

18
Ex:
class Animal:
def sound(self):
print("Animal makes a sound")
class Dog(Animal):
def bark(self):
print("Dog barks")

Animal → Parent class


Dog → Child class
Dog inherits sound() method from Animal

Disadvantages of Inheritance
Code Readability Issues
 Methods may be defined in different files or classes
 Difficult to trace where a method is implemented
Overuse Can Be Harmful
 Some problems do not naturally fit inheritance
 Using inheritance unnecessarily can make programs confusing
Alternative Approaches Exist
 Many tasks can be done without inheritance
 Sometimes composition is better than inheritance

19
20

You might also like