UNIT-4 (functional and OOPS) Flashcards

(33 cards)

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
Composition
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
Polymorphism, ex of runtime overloading
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 2. Method Overriding: Cat class overrides the speak() method class Cat(Animal): def speak(self): print("Cat meows") # Specific behavior for a Cat 3. 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 4. 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() 3. 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" 4. 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
Runtime polymorphism
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
Iterator
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
Exception handling
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
try: except:
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
Raising Exceptions
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
Matching of except blocks:
# 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
User defined exceptions
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