UNIT-4 (functional and OOPS) Flashcards

1
Q

Functional Programming

A

programs made using function

uses pure functions, recursive functions, nested functions ,lambda functions etc.

treats functions as values and pass them to functions as parameters

more readable and easily understandable.

function signature => information about them i.e.their arguments and return type etc

HIGHER ORDER FUNCTIONs
* functions that take functions as arguments, also return functions. (Ex: Callback Functions)
* understood very easily
* Testing and debugging is easier. use immutable values
* better modularity with a shorter code

  • lazy evaluation avoids repeated evaluation because the valueis evaluated and stored only when it is needed.
  • Example: Lazy Map & Lists ,tuples, sets etc
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

lamda

A

functions without the name.
=> anonymous/throw away functions.
=> number of arguments but only one expression.
=>(Implicit return)
=>used when you need a particular function for a short period of time.

ADV:
useful in defining the in-line functions.

Most suitable when it is used as a part of another function(especially with map, filter and reduce functions)

Less Code (Concise code)

Syntax: lambda input arguments: expression / Output

Input arguments: can have multiple arguments by use of commas
* Expression or output: Expression gets evaluated and results are returned

EXAMPLE:
square=lambda n : n*n
print(square(4)) #Function Call

ANOTHER EXAMPLE maximum=lambda a,b : a if a>b else b

We can use the same function definition to make two functions

def myfunc(n):
return lambda a : a * n
double_N = myfunc(2)
triple_N = myfunc(3)

print(double_N(15))
print(triple_N(15))

Output
30,45

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Map()

A

applies a function to each element of an iterable (like a list or a tuple) and returns a new iterable object.

Syntax: map(function, iterables)

  • causes iteration through iterable

is lazy

can force an iteration of the map object by passing the map object as an argument for the list or set constructor.

  • We can pass one or more iterable to the map() function.

LAZY EVALUTION
Lazy and Eager objects:
object is created when it is needed whereas eager an object is created as soon it is instantiated.

As map object can be iterated one item in eachloop. for list, all the values at one time.

optimizing code and improving performance

used to delay or avoid computations, save memory by avoiding intermediate results,

explore multiple possibilities without committing to one.
* eager evaluation is preferable when you want to perform computations as soon as possible

EXAMPLE CODE

num = (1, 2, 3, 4)
result = map(lambda x: x + x, num)
print(list(result))
Output:
<class ‘map’>
[2, 4, 6, 8]

ANOTHER EXAMPLE
num = [1, 2, 3, 4, 5]
def double_num(n):
if n% 2 == 0:
return n * 2
else:
return n

result = list(map(double_num,num)
print(result)
Output: The modified list is [1, 4, 3, 8, 5]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

stFilter()

A

filters sequence with function that tests each element in the sequence to be true or not.

filter(function,sequence/iterable)

*sequence: which needs to be filtered, it can be sets, lists, tuples, or containers of any iterators.
*Returns: an iterator that is already filtered.

CHARACTERISTICSInput : an iterable of some number of elements

  • Output: a lazy iterable
  • Elements in the output: apply the callback on each element of the iterable – if the function returns true, then the input element is
    selected else input element is rejected.

EXAMPLE
list the marks greater than 70
marks = [55, 78, 90, 87, 65, 45]
def myFunc(m):
if m <70 :
return False
else:
return True
Distinction = list(filter(myFunc, marks))
print(“Students with marks greater than 70 are”,Distinction)
Output:
Students with marks greater than 70 are [78, 90, 87]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

reduce

A

Syntax

applies a given function to the elements of an iterable ,reducing them to a single value

defined in “functools” module.

=>function argument is a function that takes two arguments and returns a single value.

=>first argument is the accumulated value, and the second argument is the current value from the iterable.

=>iterable argument is the sequence of values to be reduced.

=> initializer argument is => initial value. else, first element of the iterable is used as the initial value.

Working of reduce function:

first two elements of the sequence are picked and the result is obtained.

same function is applied to the previous result and the number after 2nd element and result is again stored

will be n – 1 calls if no initializer is specified.

final result is returned as a single value.

EXAMPLE
from functools import reduc
numbers = [1, 2, 3, 4]
def add(a, c)
return a + c

result = reduce(add, numbers)

functools.reduce(function, iterable,[initializer])
print(result)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Zip()

A

function zip => two or more iterables into a single lazy iterable of tuples.
* It does not have any callback function.

used to map the similar index of multiple containers so that they can be used just using a single entity

Elements from corresponding positions are paired
together.

The resulting iterable contains tuples

EXAMPLE without ZIP
Consider the code below which pairs the two lists:
m=[1,2,3]
n=[4,5,6]
l_new=[]
for i in range(len(m)):
l_new.append((m[i],n[i]))
print(l_new)

less code using zip. We
can observe the same output.

Syntax : zip(*iterators)
print(list(zip(m,n)))
Output
[(1, 4), (2, 5), (3, 6)]
[(1, 4), (2, 5), (3, 6)]

zipped=[(1, 4), (2, 5), (3, 6)]
SYNTAX=zip(*zipped)

UNEQUAL SIZE

Example 5: Zipping list with unequal size.(Two ways)
lis1 = [1,2,3]
lis2 = [4,5,6,7]
print(list(zip(lis1,lis2)))
The same can be acheived

using the directory comprehension as:
result={k:v for k,v in zip(lis1,lis2)}
print(result)
Output
[(1, 4), (2, 5), (3, 6)]
{1: 4, 2: 5, 3: 6}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

List comprehension

A

concise way of defining and creating a list

used to create functionality within a single line of code.

Return value is always a new list obtained by evaluating the expression in the context of for and if

*faster in processing than a list using for loop.

list = [expression for <var> in <iterable> [if condition]]</iterable></var>

m=[1,2,3]
n=[4,5,6]

print([x+y for x in m for y in n])
Output:
[5, 6, 7, 6, 7, 8, 7, 8, 9]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

POP(Procedure Oriented Programming)

A

Programming Paradigm: Style to write solution

=> uses procedures.
* Procedure: instructions used to accomplish a specific task.
=> routines, sub-routines, functions etc

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Object Oriented Programming (OOP)

A

Focus => data and the operations that manipulate the data.

code by representing real- entities as objects

to develop big and complex projects

FEATURES:
Data Abstraction:
* The way you view an object(Ex: apples)
* essential features without background details
Data encapsulation:
* Binding of data and procedures as a single unit.
* Encapsulation: a way to implement data abstraction.
Data Hiding:
* who can access the data .
=> using access specifiers.

Inheritance:
* one class (child) to derive the capabilities of another class(parent)
* Benefit: Code reusability

Polymorphism:
* object of a class to behave diff in response to the data.

KEY CONCEPTS
Class:
* method to create => entity.
* Blueprint/template for creating objects.
*a type and implementation.
* specifies set of instance vars/attributes(data each object of the class will store) and methods
(functions that define the behavior of the objects) that objects of that class has

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Syntax OOP

A

Syntax: (To create a class)
class ClassName:

<statement-1> . <statement-N>


Example 1
class Car:
#first letter should be CAP
def\_\_init\_\_(self,make,color,year ):
#Special method that creates objects
self.make=make
self.color=color
self.year=year
def drive(self):
print(""+self.make+" go vroom")
#this is a method
#self => object that uses this method

TO CREATE OBJECT
Car1=Car("BMW","Blue", "2014" )
Car1.drive()

OUTPUT:
BMW
Blue
2014
BMW go vroom
</statement-N></statement-1>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

OOPS Instances

A

instance => single object from a class. class = blueprint, and an instance => specific object built using that blueprint.

  • Represents real entities
  • Have their own attributes attributes and methods as defined by the class.

Objects have:
1.Identity: Each object = unique identity
2.Type: type() =>type of an object.
3.Value: Objects have a value that can be modified or accessed (like integers,
strings, lists)

EXAMPLE
class Car:
pass
c1 = Car()
print(c1)
print(type(c1))
print(id(c1))
Output:
<__main__.Car object at 0x000001C9E2200DC0>
<class ‘__main__.Car’>
1966593805760

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Instantiation
Constructor

A

Instantiation
* existence of a class doesn’t create
* Object must be created explicitly
* To create an object => c1= Car() => object(c1) of class Car
* (.)Dot operator -> access attributes of the class.
Ex: c1.car_name

Constructor
* special func of the class called when object is created
* __init__ => name
*invoked automatically and implicitly when object is created.
* used to initialize the internal state of an object, and create instance vars

self => reference to the object used to access
attributes and methods and should be the first parameter

Destructor
* special func => __del__, performs cleanup => when an object is deleted.
* automatically called just before an object is removed by the garbage collector.
* often used to release resources before an object is removed

module garbage collector automatically manages memory and calls destructors when objects are not needed

Destructor: Called when the object is deleted
def __del__(self):
print(f”Person {self.name} is deleted.”)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Types Of constructors

A

Fixed actual value

Types of Constructors :
1. Non Parameterized constructor
class Person:
def __init__(self):
self.name = “Joe”
#Fixed actual value
self.age = 25

def display(self):
    print(f"Name: {self.name}, Age: {self.age}") person1 = Person() person1.display()  
  1. Parameterized constructor

class Car:
def__init__(self,make,color,year ):
self.make=make
self.color=color
self.year=year
def drive(self):
print(““+self.make+” go vroom”)

Car1=Car(“BMW”,”Blue”, “2014” )
Car1.drive()

can add instance vars outside the class
p.transmission=‘M’

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Getter and Setter Method:

A

Getter:
* Used to retrieve the value of attribute of a class without directly exposing it.
Setter:
*to modify attribute of a class.
*controlled modification of attribute’s value by performing checks or
validations before assigning new value

Getter syntax:
def get_attribute(self):
return self.__attribute

Setter Syntax
def set_attribute(self, value):
self.__attribute = value

predefined functions
1 setattr() sets the value of attribute of the
Syntax setattr(object, attribute, value)
2 getattr() returns the value of the specified attribute
Syntax: getattr(object, attribute, default)
3 hasattr() returns True if the specified object has specific attribute, else False.
Syntax hasattr(object, attribute)
4 delattr() will delete the specified attribute
Syntax delattr(object, attribute)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Getter and Setter code

A

class Person:
def __init__(self, name):
self.__name = name # Private attribute

# Getter for name
def get_name(self):
    return self.\_\_name

# Setter for name
def set_name(self, name):
    self.\_\_name = name

Create an object of Person
person = Person(“Alice”)

Access name using getter
print(person.get_name()) # Output: Alice

Modify name using setter
person.set_name(“Bob”)
print(person.get_name()) # Output: Bob

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Inheritance

A

Acquiring the features of one type in another type.

  • can define a new class which inherits almost all the the properties of existing class.
  • Two relationships:
    Is – a -> parent-child relationship
  • Has – a relationship => nothing but collaboration

Benefits of inheritance:
* allows to inherit the properties of a base class, to another class
(Benefits of inheritance:
* It allows to inherit the properties of a base class, to another class
*reusability of a code.
* Allows us to add more features to a class without modifying it.
* Transitive in nature, which means that if class B inherits from class A,
then all the subclasses of B would automatically inherit from class A.
* Less development and maintenance expenses

17
Q

Is-a relationship

A

disp() method is overridden to change its behavior. Even though B inherits from A, it doesn’t call A’s disp() method but instead uses its own version.

one class gets most or all of its features from parent class.

three ways parent and child can interact.
1. Action on child imply an action on the parent

class A:
def disp(self):
print(“in disp A”)
class B(A):
pass
a1=A()
a1.disp()
b1=B()
b1.disp()
OUT: in disp A
in disp A

  1. Action on the child override the action on the parent
    class A:
    def disp(self):
    print(“in disp A”)
    class B(A):
    def disp(self):
    print(“in disp B”)
    a1=A()
    a1.disp()
    b1=B()
    b1.disp()
    Out:in disp A
    in disp B
  1. Action on the child alter the action on the parent’

class A:
def disp(self):
print(“in disp A”)
class B(A):
def disp(self):
A.disp(self)
print(“in disp B”)
a1=A()
a1.disp()
b1=B()
b1.disp()

Output:
in disp A
in disp A
in disp B

18
Q

Types of Is-a Relationship

A
  1. Single level inheritance:
    Sub classes inherit one super class.
  2. Multi Level inheritance: inherited from another class which is inherited from another class

flexibility to inherit from more than one class
turn inherited from another class and so on.

Multiple inheritance: can have more than one super class and inherit the features from all parent classes.

subclass inherits from another subclass, forming a hierarchical chain of classes.

  1. Hierarchical inheritance: One class serves as super class for more than one
    sub classes
  2. Hybrid inheritance: A mix of two or more above types of inheritance. => Diamond shaped inheritance
19
Q

single level inheritance /parent child example

A

Superclass
class Person:
def __init__(self, name, id_no):
self.name = name
self.id_no = id_no

def Display(self):
    print(f"Person: {self.name}, ID: {self.id_no}")

Subclass
class stud(Person):
def __init__(self, name, id_no):
# Explicitly call the parent class constructor
Person.__init__(self, name, id_no)

def Print(self):
    print("stud class called")

Creating an object of Person
p = Person(“Akash”, 1001)
p.Display()

Creating an object of stud
student = stud(“Madan”, 103)
student.Print()
student.Display()

20
Q

super function()

A

Creating an object of Person

built-in function => access methods and properties from a parent class => subclass.
* overridden method as well and parent method is required. => super()

Superclass
class Person:
def __init__(self, name, id_no):
self.name = name
self.id_no = id_no

def Display(self):
    print(f"Person: {self.name}, ID: {self.id_no}")

Subclass
class Student(Person): # More meaningful name
def __init__(self, name, id_no):
super().__init__(name, id_no) # Using super()

def Print(self):
    print("Student class called")

p = Person(“Akash”, 1001)
p.Display()

Creating an object of Student
student = Student(“Madan”, 103)
student.Print()
student.Display()

OVERIDDING

Parent Class
class Person:
def __init__(self, name):
self.name = name

def display(self):
    print(f"Name: {self.name}")

Child Class
class Employee(Person):
def __init__(self, name, salary):
super().__init__(name) # Call the parent class constructor
self.salary = salary

def display(self):
    super().display()  # Call the parent class method
    print(f"Salary: {self.salary}")

Create an Employee object
emp = Employee(“Alice”, 50000)
emp.display()
# Call the display method from Employee (which overrides Person’s display)

OUTPUT:
Name: Alice
Salary: 50000

21
Q

Multiple inheritance

A

Parent Class 1
class Person:
def __init__(self, name):
self.name = name

Parent Class 2
class Employee:
def __init__(self, salary):
self.salary = salary

Child Class inheriting from both Person and Employee
class Manager(Person, Employee):
def __init__(self, name, salary, department):
Person.__init__(self, name)
Employee.__init__(self, salary)
self.department = department

Create Manager object
manager = Manager(“Alice”, 75000, “HR”)
print(manager.name)
# From Person
print(manager.salary)
# From Employee
print(manager.department) # From Manager

OUTPUT:
Alice
75000
HR

22
Q

Hierarchical inheritance

A

Parent Class
class Person:
def __init__(self, name):
self.name = name

def display_person(self):
    print(f"Name: {self.name}")

Child Class 1 inheriting from Person
class Employee(Person):
def __init__(self, name, salary):
super().__init__(name) # Call the Parent class constructor
self.salary = salary

def display_employee(self):
    print(f"Salary: {self.salary}")

Child Class 2 inheriting from Person
class Student(Person):
def __init__(self, name, grade):
super().__init__(name) # Call the Parent class constructor
self.grade = grade

def display_student(self):
    print(f"Grade: {self.grade}")

Create objects of Employee and Student
employee = Employee(“Alice”, 50000)
student = Student(“Bob”, “A”)

Call methods from the parent and child classes
employee.display_person() # From Person class
employee.display_employee() # From Employee class

student.display_person() # From Person class
student.display_student() # From Student class

OUTPUT
Name: Alice
Salary: 50000
Name: Bob
Grade: A

23
Q

Hybrid inheritance

A

Parent Class 1
class Person:
def __init__(self, name):
self.name = name

def display_person(self):
    print(f"Name: {self.name}")

Parent Class 2
class Employee:
def __init__(self, salary):
self.salary = salary

def display_employee(self):
    print(f"Salary: {self.salary}")

Child Class 1 inheriting from Person (Single Inheritance)
class Manager(Person):
def __init__(self, name, department):
super().__init__(name)
self.department = department

def display_manager(self):
    print(f"Department: {self.department}")

Child Class 2 inheriting from both Person and Employee (Multiple Inheritance)
class Executive(Manager, Employee):
def __init__(self, name, salary, department, position):
Manager.__init__(self, name, department)
Employee.__init__(self, salary)
self.position = position

def display_executive(self):
    print(f"Position: {self.position}")

Create an object of Executive (Hybrid Inheritance)
exec = Executive(“John”, 100000, “Finance”, “CEO”)

Call methods from different levels and classes
exec.display_person() # From Person class
exec.display_manager() # From Manager class
exec.display_employee() # From Employee class
exec.display_executive() # From Executive class

Name: John
Department: Finance
Salary: 100000
Position: CEO

24
Q

issubclass() and isinstance() methods

A

issubclass(sub, sup)
checks the btw the specified classes.
Returns True if the first class is the subclass of the second else False

isinstance(obj,class)
checks the relationship btw the objects and classes.
Returns True if the object is the instance of the specified class.

EX CODE
# Parent Class
class Person:
def __init__(self, name):
self.name = name

Child Class
class Employee(Person):
def __init__(self, name, salary):
super().__init__(name)
self.salary = salary

Create an object of Employee class
emp = Employee(“Alice”, 50000)

Using issubclass() to check class inheritance

print(issubclass(Employee, Person)) # True, Employee is a subclass of Person
print(issubclass(Person, Employee)) # False, Person is not a subclass of Employee

Using isinstance() to check if an object is an instance of a class
print(isinstance(emp, Employee)) # True, emp is an instance of Employee
print(isinstance(emp, Person)) # True, emp is also an instance of Person (since Employee inherits from Person)
print(isinstance(emp, object)) # True, everything is an instance of object in Python

25
Q

Composition

A

class contains an instance(object) of another class as one of its attributes,

“has-a” relationship:

EX CODE
class Engine:
def start(self):
print(“Engine starting…”)

Car class contains an Engine (Composition)
class Car:
def __init__(self):
self.engine = Engine() # Car has an engine

def start_car(self):
    self.engine.start()  # Access engine's start method

Create a Car object
car = Car()
car.start_car()

26
Q

Polymorphism, ex of runtime overloading

A

Polymorphism => having multiple forms.

  • same function name, but with diff signatures

allows objects of diff classes to be treated as objects of a common superclass.
* enables a single interface to be used for entities of diff types

RUNTIME OVERLOADING CODE EX:

  1. Inheritance: Parent Class (Superclass)
    class Animal:
    def speak(self):
    print(“Animal makes a sound”) # Default behavior for an animal
  2. Method Overriding: Dog class overrides the speak() method
    class Dog(Animal):
    def speak(self):
    print(“Dog barks”) # Specific behavior for a Dog
  3. Method Overriding: Cat class overrides the speak() method
    class Cat(Animal):
    def speak(self):
    print(“Cat meows”) # Specific behavior for a Cat
  4. Dynamic Binding: Function that calls the appropriate speak() method
    def animal_sound(animal):
    animal.speak() # Method that is dynamically bound based on the actual object type
  5. Common Interface: All subclasses share the same ‘speak’ method interface
    def make_animal_speak(animal):
    print(f”{animal.__class__.__name__} says: “, end=””)
    animal.speak() # Common interface for all subclasses to implement ‘speak’

Create instances of Dog and Cat
dog = Dog()
cat = Cat()

  1. Dynamic Binding: Dynamic method call based on the object passed
    animal_sound(dog) # Dog object -> Output: “Dog barks”
    animal_sound(cat) # Cat object -> Output: “Cat meows”
  2. Common Interface: Dog and Cat share the common ‘speak’ method interface
    make_animal_speak(dog) # Dog object -> Output: “Dog barks”
    make_animal_speak(cat) # Cat object -> Output: “Cat meows”

OUTPUT:
Dog barks
Cat meows
Dog says: Dog barks
Cat says: Cat meows

27
Q

Runtime polymorphism

A

supports runtime polymorphism by => method overloading and method overriding

ability of an object to behave differently based on its actual type during program execution
=>dynamic polymorphism
* enables the same method name to behave differently based on
the specific class instance at runtime.

Key Aspects
1.Inheritance:
* closely associated with inheritance.
* Subclasses inherit methods from superclass, and they can provide implementation for these methods.
2.Method Overriding:
* Subclasses override methods =>own implementation.
* method signature remains the same in both the superclass and subclass.
3.Dynamic Binding:
* decision about which method to call being made at runtime,
*based on the actual type of object invoking the method
4.Common Interface:
* Different subclasses sharing a common superclass interface
* diff behavior based on specific implementations.

28
Q

Iterator

A

object that allows iteration through a sequence of elements, one at a time. using:
__iter__():returns iterator object itself and is called when iterator is initialized.
__next__(): returns the next item in the sequence.

When no more elements raises=>
StopIterationexception.

Lazy Evaluation: generate values on-demand rather than computing all values at once.

memory-efficient => dealing with large datasets => only retrieves elements as needed.

container class (like list) should support this funcs
iter(container-object)) returns an object of a class => iterator.
next(iterator_object))

interfaces =>implemented by going through container

CODE EXAMPLE

Define the container class
class MyContainer:
def __init__(self, data):
self.data = data
self.index = 0

# \_\_iter\_\_ method returns the iterator (self)
def \_\_iter\_\_(self):
    return self

# \_\_next\_\_ method returns the next item in the data list
def \_\_next\_\_(self):
    if self.index < len(self.data):
        item = self.data[self.index]
        self.index += 1
        return item
    else:
        raise StopIteration  # Stop iteration when data is exhausted

Create an instance of MyContainer
container = MyContainer([10, 20, 30])

Get the iterator object from container
iterator = iter(container)

Use next() to print each item from the iterator
print(next(iterator)) # Output: 10
print(next(iterator)) # Output: 20
print(next(iterator)) # Output: 30

OR
for item in container:
print(item)

used for both iter and next

29
Q

Exception handling

A

deal with errors or exceptional situations => program execution.
*allows manage these situations instead =>
program crash.
* try-block, except, else, raise

Program can produce some errors even if the program is perfect.

due to:
Exceptional situations
data is malformed

  1. Syntax errors
    when there a deviation from the rules of the lang.
    => parser discovers these If hybrid interpreter, compiler finds error.
  2. Runtime Errors (Exceptions)
    errors detected during execution => disrupts flow of execution of instructions.
    Ex: Print(“Good Morning”)
    #NameError: No name ‘Print’ found

2 categories
Built-In exception (System defined exceptions )
2. User defined exceptions

Exceptions Explanation:
Keyboard Interrupt: users hit Ctrl-C, => interrupt key
Overflow Error:
when a floating-point expression => large value ZeroDivision: divide by 0
IO Error: sequence index is outside the range of valid indexes
Name Error: evaluate an unassigned identifier
Type Error: operation or function is applied to an object wrong type

30
Q

try:
except:

A

Try
code => exception (error).

  • handles exceptions in try-block, not in the other handlers of the same try block.

except :
* exception in try block, caught in except block and block executed.
* multiple exceptions as a parameterized tuple.
*many except clauses => specific classes specified => parent classes specified
* Last except clause provide a common/default way of handling all exceptions

else :
* This block will be executed if no errors were raised.
block gets executed when try is successful

Finally:
* statements executed regardless of exception/ or not in the try block.
* performs clean up actions or tasks and close there sources used in the program.

raise
* used to forcefully throw an exception

Try, except:
try:
print(x)
except: #default block
print(“An exception occurred as x is not defined “)

with try, except ,else, finally)
try:
result = 10 / 0 # a ZeroDivisionError
except ZeroDivisionError as e:
#Catches any type of exception and prints a general error message.
print(“Error:”, e) # Handling the ZeroDivisionError
else:
print(“No exceptions occurred.”)
finally:
print(“This will always execute, regardless of exceptions.”)

Output:
Error: division by zeroThis will always execute,regardless of exceptions.

31
Q

Raising Exceptions

A

Raising Exceptions:
Exceptions raised manually => raise statement =>
custom exceptions. => raise built in exceptions

try:
age = int(input(“Enter your age: “))
if age < 0:
raise ValueError(“Age cannot be negative.”)
except ValueError as e:
#as: => assigns the error details to a var=> can print or use them=>can access info about exception
print(“Error:”, e)

Output:
Enter your age: -7
Error: Age cannot be negative.

EXAMPLE OF AS
print(“Exception type:”, type(e).__name__)
#name of error

32
Q

Matching of except blocks:

A

This won’t execute

raised exception object is matched with except blocks in order in which they occur in the try-except statement.

*code after first match is executed.
try:
x = 1 / 0 # This raises a ZeroDivisionError
except ArithmeticError:
print(“ ArithmeticError”) # This matches first
except ZeroDivisionError:
print(“ZeroDivision”)

*first match and not best match.

try:
x = 1 / 0 # Raises ZeroDivisionError
except Exception:
print(“Caught a general Exception”) # General match
except ZeroDivisionError:
print(“Caught a ZeroDivisionError”)
# More specific, but ignored

  • If no match=> default except block, => executed

try:
print(undefined_variable) # Raises NameError
except ZeroDivisionError:
print(“ZeroDivisionError”) # Doesn’t match
except:
print(“Caught some other error”) # Default block

OUTPUT:
Caught some other error

33
Q

User defined exceptions

A

custom exceptions=> by a new class.
has to be derived, either directly or indirectly, from
built-in Exception class. *Most built-in exceptions => derived from this class.
*The new exception => using the raise statement

EXAMPLE CODE

class MyException(Exception): # Custom exception class
def __init__(self, message):
self.message = message
def __str__(self):
return self.message

Check whether n is between 1 and 100
try:
n = int(input(“Enter the number: “)) # Takes an integer input
if not 1 <= n <= 100: # Check if n is within the range [1, 100]
raise MyException(“Number not in range”) # Raise a custom exception if invalid
except MyException as e:
print(e) # Catch and display the custom exception message
else:
print(“Number well within the range”) # Executes if no exception was raised
finally:
print(“Program Terminated”) # Executes regardless of whether an exception was raised