OOP Python 1
OOP Python 1
Prepared By
-Anooja Joy
Object Oriented VS Procedural
In a procedural programming, the entire code is written into one long
procedure even though it might contain functions and subroutines. It is not
manageable as both data and logic get mixed together. Adding new data
and function is not easy. Procedural programming does not have any
proper way for hiding data so it is less secure.
In object-oriented programming, the program is split into self-contained
Object
Inheritance
Polymorphism
Method Overriding
Data Abstraction
Encapsulation
What is Python Class?
A class in python is the blueprint from which specific objects are
created.
Why Class is required?
Classes allow us to logically group our data and function in a way
can be printed
Attribute Description
__dict__ It provides the dictionary containing the information about the class namespace.
Function Description
name __new__.
when you call Example(), to create an object of the class Example,
then the __new__ method of this class is called. Python defines this
function for every class by default. But we can redefine it
class Example:
def __new__(self):
return “hello”
Obj = Example()
type(Obj)
class Example:
count=1 #class variable
Obj = Example()
type(Obj)
Name Space
A namespace(collection of names) is a mapping from names to
objects. Most namespaces are currently implemented as Python
dictionaries.
Everything in Python is an object and the Name is a way to access
the underlying object.
To get the address (in RAM) of some object through the built-in
function id()
a = 2
print('id(a) =', id(a))
a = a+1
print('id(a) =', id(a))
print('id(3) =', id(3))
b = 2
print('id(b) =', id(b))
print('id(2) =', id(2))
Deleting object
c1 = ComplexNumber(1,3)
del c1
a new instance object is created in memory and the name c1 binds
with it.
On the command del c1, this binding is removed and the
name c1 is deleted from the corresponding namespace. The object
however continues to exist in memory and if no other name is
bound to it, it is later automatically destroyed.
This automatic destruction of unreferenced objects in Python is also
called garbage collection.
Destroying Objects (Garbage Collection)
Python deletes unneeded objects (built-in types or class instances)
automatically to free the memory space. The process by which
Python periodically reclaims blocks of memory that no longer are in
use is termed Garbage Collection.
Python's garbage collector runs during program execution and is
triggered when an object's reference count reaches zero.
An object's reference count increases when it is assigned a new
name or placed in a container (list, tuple, or dictionary). The
object's reference count decreases when it's deleted with del, its
reference is reassigned, or its reference goes out of scope. When an
object's reference count reaches zero, Python collects it
automatically.
a class can implement the special method __del__(), called a
destructor, that is invoked when the instance is about to be
destroyed. This method might be used to clean up any non memory
resources used by an instance.
EXAMPLE
class Point:
def __init__( self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print class_name, "destroyed"
pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3)
# prints the ids of the obejcts
del pt1
del pt2
del pt3
Constructor
Purpose:
A constructor is a special type of method (function) with no explicit
return type which allows you to create an object of class and is
used to initialize instance members/ attributes of instance of the
class.
the constructor method is invoked automatically whenever a new
object of a class is instantiated.
Constructors also verify that there are enough resources for the object
to perform any start-up task.
Executed when: Constructor definition is executed when we
create the object of this class.
Types: Constructors can be of two types.
Parameterized Constructor
Non-parameterized Constructor
How? In python, the method __init__ simulates the constructor of
the class. It gets called whenever a new object of class is instantiated.
Normally constructor don’t returns anything ie none.(since
separation of data and logic is needed)
EXAMPLE
class Employee:
def __init__(self,name,id):
self.id=id
self.name=name
def display(self):
print("ID:",self.id,"\nName:",self.name)
emp1=Employee("John",101)
emp2=Employee("Did",102)
#accessing display() method to print employee1 information
emp1.display()
#accessing display() method to print employee2 information
emp2.display()
Parametrized VS Non- Parametrized
class Student: class Student:
# Constructor - # Constructor -
parameterized non parameterized
def __init__(self,name): def __init__(self):
print("This is non
print("This is parametrized parametrized constructor")
constructor") def show(self,name):
self.name=name print("Hello",name)
def show(self): student=Student()
student.show("John")
print("Hello",self.name)
student=Student("John")
student.show()
Variables Assocciated with a class
1. Class variable/Static variable is a variable that is shared by all the
different objects/instances of a class. Its value is assigned in class and
outside normal methods.
Class attributes are accessed using the name of the class.
Changing the class attribute using the class name will be reflected for
nested function
a function can return another function.
accessible from outside the class. The object of the same class is
required to invoke a public method.
Protected members of a class are accessible from within the class
outside the class. They can be handled only from within the class.
Access modifiers play an important role to protect the data from
unauthorized access as well as protecting it from getting manipulated.
When inheritance is implemented there is a huge risk for the data to get
destroyed(manipulated) due to transfer of unwanted data from the parent
class to the child class. Therefore, it is very important to provide the right
access modifiers for different data members and member functions
depending upon the requirements.
The arrangement of private instance variables and public methods
ensures the principle of data encapsulation means to restrict class
variable’s access outer class methods.
Access Specifiers in Python
Python does not support access control.Python doesn't have any
mechanism that effectively restricts access to any instance
variable/method.
All members in a Python class are public by default. Any member can be
accessed from outside the class environment.
from our parent class. Then we can overwrite and add new functionalities
without affecting the parent class.
The newly formed class is a derived class (or child class or sub-class).
The existing class is a base class (or parent class or super class).
Syntax:
class derived-class(base class):
<class-suite>
EXAMPLE
class Animal:
def speak(self):
print("Animal Speaking")
#child class Dog inherits the base class Animal
class Dog(Animal):
def bark(self):
print("dog barking")
class Cat(Animal):
pass
d=Dog()
c=Cat()
d.bark()
d.speak()
c.speak()
Inheritance comes into picture when a new class possesses the 'IS A'
relationship with an existing class.
Message Communication
Accessing attributes and methods of one class in another class
Accessing attributes and methods of one class in another class is done by
passing the object of one class to another.
class ClassA():
def __init__(self):
self.var1 = 1
self.var2 = 2
def methodA(self):
self.var1 = self.var1 + self.var2
return self.var1
class ClassB(ClassA):
def __init__(self, class_a):
self.var1 = class_a.var1
self.var2 = class_a.var2
object1 = ClassA()
summ = object1.methodA()
print(summ)
object2 = ClassB(object1)#MESSAGE COMMUNICATION
print(object2.var1)
print(object2.var2)
Initialization of parent class
attributes
If you forget to invoke the __init__() of the parent class then its
instance variables would not be available to the child class.
#Single Inheritance
class A:
def __init__(self,n='Rahul'):
self.name=n
class B(A):
def __init__(self,roll):
#A.__init__(self,n='Rahul')
self.roll = roll
object=B(23)
print (object.name)
Object Class
In Python (from version 3.x), object is root of all classes.
class Calculation1:
def Summation(self,a,b):
return a+b
class Calculation2:
def Multiplication(self,a,b):
return a*b
class Derived(Calculation1,Calculation2):
def Divide(self,a,b):
return a/b
d=Derived()
print(d.Summation(10,20))
print(d.Multiplication(10,20))
EXAMPLE 2
class Base1:
def __init__(self):
self.str1 = "Super Class"
print("Base1")
class Base2:
def __init__(self):
self.str2 = "Sub class"
print("Base2")
class Derived(Base1, Base2):
def __init__(self):# Calling constructors of Base1 and Base2
classes
Base1.__init__(self)
Base2.__init__(self)
print("Derived class showing multiple inheritance")
def printStrs(self):
print(self.str1, self.str2)
ob = Derived()
ob.printStrs()
Multilevel Inheritance
Multi-Level inheritance is possible in python
#Multilivel Inheritance
class Animal:
def speak(self):
print("Animal Speaking")
#The child class Dog inherits the base class Animal
class Dog(Animal):
def bark(self):
print("dog barking")
#The child class Dogchild inherits another child class Dog
class DogChild(Dog):
def eat(self):
print("Eating bread...")
d=DogChild()
d.bark()
d.speak()
d.eat()
METHOD RESOLUTION ORDER
Method Resolution Order(MRO) denotes the way a programming language
resolves a method or attribute or the order in which the base classes are
searched when executing a method. It's the order in which method should be
inherited in the presence of multiple inheritance.
In multiple inheritance scenario, the method or attribute is searched first within the
current class. If not found, the search continues into parent classes in depth-first,
left-right fashion without searching same class twice. The methods are executed
based on the order specified while inheriting the classes.This order is also called
Linearization of a class and set of rules are called MRO(Method Resolution Order).
class A:
def meth(self):
print(" In class A")
class B(A):
def meth(self):
print(" In class B")
class C(A):
def meth(self):
print("In class C")
class D(B,C):
pass
r=D()
MRO
MRO of a class can be viewed as the __mro__ attribute
or mro() method. The former returns a tuple while latter returns a
list.
Syntax: classname.__mro__ OUTPUT
or classname.mro()
In class C
Example:
class A: (<class '__main__.C'>, <class
'__main__.A'>, <class '__main__.B'>,
def meth(self):
<class 'object'>)
print(" In class A")
[<class '__main__.C'>, <class
class B: '__main__.A'>, <class '__main__.B'>,
def meth(self): <class 'object'>]
print(" In class B")
class C(A,B):
def meth(self):
print("In class C")
r=C()
r.meth()
print(C.__mro__)
Other cases of MRO
class A: OUTPUT
def process(self): C process()
print('A process()') [<class '__main__.D'>, <class
class B: '__main__.C'>, <class
def process(self): '__main__.A'>, <class
'__main__.B'>, <class
print('B process()')
'object'>]
class C(A, B):
def process(self):
print('C process()')
class D(C,B):
pass
obj = D()
obj.process()
print(D.mro())
Other cases of MRO
class A: OUTPUT
def process(self): A process()
print('A process()') [<class '__main__.D'>, <class
class B: '__main__.C'>, <class
def process(self): '__main__.A'>, <class
'__main__.B'>, <class
print('B process()')
'object'>]
class C(A, B):
pass
class D(C,B):
pass
obj = D()
obj.process()
print(D.mro())
Other cases of MRO
class A: OUTPUT
def process(self): C process()
print('A process()') [<class '__main__.D'>, <class
class B(A): '__main__.B'>, <class
pass '__main__.C'>, <class
'__main__.A'>, <class
'''def process(self):
'object'>]
print('B
process()')'''
class C(A):
def process(self):
print('C process()')
class D(B,C):
pass
obj = D()
obj.process()
print(D.mro())
Other cases of MRO
class A:
def process(self):
print('A process()')
class B(A):
def process(self):
print('B process()')
class C(A, B):
pass
obj = C()
obj.process()
OUTPUT
--------- TypeError Traceback (most recent call
last) <ipython-input-8-868896ad885b> in
<module> 6 def process(self): 7 print('B
process()') ----> 8 class C(A, B): 9 pass 10 obj
= C() TypeError: Cannot create a consistent
method resolution order (MRO) for bases A, B
Other cases of MRO
class X: pass
class Y: pass
class Z: pass
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
p1 = Point(2,3)
Print(p1)
Operator Overloading with Special
Function
add__ is a magic method which can be overridden. In Python,
numbers are not primitive literals but objects.
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
def __add__(self,other):
x = self.x + other.x
y = self.y + other.y
return Point(x,y)
p1 = Point(2,3)
p2 = Point(-1,2)
print(p1 + p2)
Overloading Comparison Operators
Python does not limit operator overloading to arithmetic operators
only. We can overload comparison operators as well
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
def __lt__(self,other):
self_mag = (self.x ** 2) + (self.y ** 2)
other_mag = (other.x ** 2) + (other.y ** 2)
return self_mag < other_mag
Point(1,1) < Point(-2,-3)
Point(1,1) < Point(0.5,-0.2)
METHOD OVERLOADING
Method Overloading means same function name but different
signatures or being used for different types.
python does not supports method overloading. We may overload
the methods but can only use the latest defined method.
Used for different types
# len() being used for a string
print(len("geeks"))
# len() being used for a list
print(len([10, 20, 30]))
Different signatures
def add(x, y, z = 0):
return x + y+z
# Driver code
print(add(2, 3))
print(add(2, 3, 4))
Method overloading using * args
mimics
def add(datatype, *args):
# if datatype is int initialize answer as 0
if datatype =='int':
answer = 0
# if datatype is str initialize answer as ''
if datatype =='str':
answer =''
# Traverse through the arguments
for x in args:
# This will do addition if the arguments are int. Or
concatenation if the arguments are str
answer = answer + x
print(answer)
#Integer
add('int', 5, 6)
# String
add('str', 'Hi ', 'Hello')
Polymorphism using Common
Interface
A program to demonstrate the usage of function that can take any object.
Here function flying_test acts as interface.
class Parrot:
def fly(self):
print("Parrot can fly")
def swim(self):
print("Parrot can't swim")
class Penguin:
def fly(self):
print("Penguin can't fly")
def swim(self):
print("Penguin can swim")
def flying_test(bird): # common interface
bird.fly()
blu = Parrot() #instantiate objects
peggy = Penguin()
flying_test(blu) # passing the object
flying_test(peggy)
DATA ABSTRACTION,
ENCAPSULATION, INFORMATION
HIDING
Encapsulation
Encapsulation is defined as the wrapping up of data under a single unit.
It binds together code and the data. It prevents the data from being
accessed by the code outside ie hiding the private details of a class from
other objects.
In encapsulation, the variables or data of a class is hidden from any
other class and can be accessed only through any member function of
its own class in which it is declared.
As in encapsulation, the data in a class is hidden from other classes
class as private and writing public methods in the class to set and get
the values of variables
JAVA EXAMPLE
/An Account class which is a fully encapsulated //A Java class to test the encapsulated class
class Account { Account.
private long acc_no; //private data members public class TestEncapsulation {
private String name,email; public static void main(String[] args) {
private float amount; Account acc=new Account();
public long getAcc_no() { //public getter and
//setting values through setter methods
setter methods
acc.setAcc_no(7560504000L);
return acc_no; }
acc.setName("Sonoo Jaiswal");
public void setAcc_no(long acc_no) {
acc.setEmail("sonoojaiswal@gmail.co
this.acc_no = acc_no; }
m");
public String getName() {
acc.setAmount(500000f);//getting valu
return name; }
es through getter methods
public void setName(String name) {
this.name = name;} System.out.println(acc.getAcc_no()+"
public String getEmail() { "+acc.getName()+" "+acc.getEmail()+"
return email;} "+acc.getAmount()); }
public void setEmail(String email) { }
this.email = email;}
public float getAmount() {
return amount; }
public void setAmount(float amount) {
this.amount = amount;} }
Encapsulation, Hiding &
Abstraction
Information hiding is the principle that some internal information or
data is "hidden", so that it can't be accidentally changed
In encapsulation, the variables of a class will be hidden from other
classes, and can be accessed only through the methods of their
current class. Therefore, it is also known as data hiding.
Data Abstraction = Data Encapsulation + Data Hiding
Benefits of Encapsulation
The fields of a class can be made read-only or write-only.
A class can have total control over what is stored in its fields.
Encapsulating Data
Traditional object-oriented languages like Java and C# use getter
and setter method to access encapsulated data or private
data. They are also known as mutator methods.
Getter Method is used for retrieving data and setter method is
and deleter.
If no arguments are given, property() method returns a base
getter function.
EXAMPLE
class Person: #property()
def __init__(self, name):
self._name = name
def getName(self):
print('Getting name')
return self._name
def setName(self, value):
print('Setting name to ' + value)
self._name = value
def delName(self):
print('Deleting name')
del self._name
# Set property to use getName, setName
# and delName methods
name = property(getName, setName, delName, 'Name property')
p = Person('Adam')
print(p.name)
p.name = 'John'
Property()
A class in Python can also include properties by using the property() function.
The property() method in Python provides an interface to instance attributes
and encapsulate it.
The property() method takes the get, set and delete methods as arguments
and returns an object of the property class. It encapsulates instance
attributes and provides a property, same as Java and C#.
Syntax: prop=property(getter, setter, deleter, docstring)
class person:
def __init__(self):
self.__name=‘’
def setname(self, name):
print('setname() called')
self.__name=name
def getname(self):
print('getname() called')
return self.__name
name=property(getname, setname)
from person import person
p1=person()
p1.name="Steve“
Property() with deleter
class person:
def __init__(self, name):
self.__name=name
def setname(self, name):
print('setname() called')
self.__name=name
def getname(self):
print('getname() called')
return self.__name
def delname(self):
print('delname() called')
del self.__name
name=property(getname, setname, delname)
from person import person
p1=person()
p1.name="Steve“
del p1.name
@property Decorator
@property decorator allows us to define properties easily without
calling the property() function manually.
class person:
def __init__(self):
self.__name='‘
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
self.__name=value
p=person()
p.name='Steve'
p.name
@setter and @deleter
Use @[property-name].setter to call a setter method and @[property-
name].deleter to call deleter method.
class person:
def __init__(self):
self.__name=''
@property
def name(self):
return self.__name
@name.sette
def name(self, value):
self.__name=value
@name.deleter
def name(self, value):
print('Deleting..')
del self.__name
p=person()
p.name='Steve'
p.name
del p.name
Data Hiding
In Python, data hiding is achieved by using double underscore (__)
before the attributes name to hide it.
After this, the attribute will not be visible outside of the class
through the object.
access of hidden variable outside the class using object will threw
an exception.
To change the value of hidden variables use a setter function which
takes hidden variable as parameter.
In Python, we denote private attribute using underscore as prefix
double “ __“.
So variables can be treated as private data members
Data Hiding
class MyClass:
__hiddenVariable = 0 # Hidden member of MyClass
emp = Employee()
emp2 = Employee()
try:
print(emp.__count)
finally:
emp.display()
Changing value of hidden variable
class Computer:
def __init__(self):
self.__maxprice = 900
def sell(self):
print("Selling Price: {}".format(self.__maxprice))
def setMaxPrice(self, price):
self.__maxprice = price
c = Computer()
c.sell()
# change the price
c.__maxprice = 1000
c.sell()
# using setter function
c.setMaxPrice(1000)
c.sell()
ABSTRACT CLASS
Abstract classes are classes that contain one or more abstract methods.
An abstract method is a method that is declared, but contains no
implementation. Abstract method decorator should be added
Abstract classes may not be instantiated, and require subclasses to provide
implementations for the abstract methods. Subclasses of an abstract class
in Python are not required to implement abstract methods of the
parent class.
Python on its own doesn't provide abstract classes. Yet, Python comes with a
module which provides the infrastructure for defining Abstract Base Classes
(ABCs). This module is called - for obvious reasons - abc.
Abstract class cannot be instantiated. This means you cannot create objects
or instances for these classes. It can only be used for inheriting certain
functionalities which you call as a base class. So you can inherit functionalities
but at the same time, you cannot create an instance of this particular class.
A class that is derived from an abstract class cannot be instantiated unless all
of its abstract methods are overridden. Ie, Sub-class inheriting abstract
classes should provide definition of abstract method else it will throw
an error.
NOTE: An abstract method can have an implementation in the abstract
class! Even if they are implemented, designers of subclasses will be
forced to override the implementation.
Data Abstraction
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
def __init__(self, value):
self.value = value
@abstractmethod
def do_something(self):
pass
from abc import ABC, abstractmethod
class Employee(ABC):
@abstractmethod
def calculate_salary(self,sal):
pass
class Developer(Employee):
def calculate_salary(self,sal):
finalsalary= sal*1.10
return finalsalary
emp_1=Developer()
print(emp_1.calculate_salary(10000))
from abc import ABC, from abc import ABC, abstractmethod
abstractmethod class AbstractClassExample(ABC):
class def __init__(self, value):
AbstractClassExample(ABC):
self.value = value
def __init__(self,
super().__init__()
value):
@abstractmethod
self.value =
value def do_something(self):
pass
super().__init__() class
@abstractmethod DoAdd42(AbstractClassExample):
def def do_something(self):
do_something(self): return self.value + 42
pass
class
class DoMul42(AbstractClassExample):
DoAdd42(AbstractClassExample
def do_something(self):
):
pass return self.value * 42
x = DoAdd42(4)#will throw x = DoAdd42(10)
error y = DoMul42(10)
print(x.do_something())
print(y.do_something())
EXAMPLE
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
@abstractmethod
def do_something(self):
print("Some implementation!")
@abstractmethod
def another_method(self):
pass
class AnotherSubclass(AbstractClassExample):
def do_something(self):
super().do_something()
print("The enrichment from AnotherSubclass")
def another_method(self):
print("this is also implemented")
x = AnotherSubclass()
x.do_something()
EXCEPTION HANDLING IN PYTHON
Errors & Exceptions
In Python, abnormal behavior can be due to an error or an exception. A
Python program terminates as soon as it encounters an error.
1. Errors can be Syntax Error Error(due to poor understanding of Language ie
when the parser detects an incorrect statement due to improper structure
(syntax) of the language) and Logical Error(due to poor understanding of
problem).
print( 4 / 2 ) )
File "<stdin>", line 1 print( 4 / 2 )) ^
SyntaxError: invalid syntax
2. Exception: Even if a statement or expression is syntactically correct, it may
cause an error when an attempt is made to execute it. Errors detected during
execution are called exceptions. An exception is an error or abnormal
condition that happens during execution of a program which can cause
termination of program. Exceptions can be synchronous exception(divide by
zero, araay index out of bound) which are controlled by program and
asynchronous exception(hardware malfunction, disk failure, keyboard
interrupt). Eg: IndexError, ImportError, IOError, ZeroDivisionError, TypeError.
Most exceptions are not handled by programs, however, and result in error
messages as shown
10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
Tracebacks are generated due to runtime errors.
ERROR HANDLING
Python provides two very important ways to handle any unexpected
error:
Exception Handling : An exception is an event, which occurs during
the execution of a program that disrupts the normal flow of the
program's instructions.
Assertions: An assertion is a sanity-check that you can turn on or
turn off when you are done with your testing of the program.
Exception Handling in Python
An exception is an event which occurs during execution of a
program and disrupts normal flow of execution.
Since program cannot handle the situation it raises an exception which
is a python object that represents the error.
When a program generate an exception it must be be handled, which
avoids your program to crash.
print( 0 / 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
In the above code exceptions are not handled and error message of string
type indicating type of exception is printed. It’s a built in exception.
Exception is the base class for all the exceptions in python.
Python provides us some basic exception classes which are already defined
under Exception class and can be used in generic cases.
Built in Exception Classes
Exception Class Event
ArithmeticError Raised when numeric calculations fails
FloatingPointError Raised when a floating point calculation fails
Raised when division or modulo by zero takes place for
ZeroDivisionError
all numeric types
AssertionError Raised when Assert statement fails
Raised when result of an arithmetic operation is too
OverflowError
large to be represented
ImportError Raised when the imported module is not found
IndexError Raised when index of a sequence is out of range
KeyboardInterrup Raised when the user interrupts program execution,
t generally by pressing Ctrl+c
IndentationError Raised when there is incorrect indentation
SyntaxError Raised by parser when syntax error is encountered
Raised when the specified key is not found in the
KeyError
dictionary
Raised when an identifier is not found in the local or
NameError
global namespace
Exception Handling in Python
Exception handling in Python is done by following methods:
Try block: Python executes code following the try statement as a
the absence of exceptions. It lets you code sections that should run only
when no exceptions are encountered in the try clause.
Finally: finally enables you to execute sections of code that should always
try:
print("try block")
x=int(input('Enter a number: '))
y=int(input('Enter another number: '))
z=x/y
except ZeroDivisionError:
print("except ZeroDivisionError block")
print("Division by 0 not accepted")
finally:
print("finally block")
print ("Out of try, except, else and finally blocks." )
Raising an Exception
raise : It is used to throw an exception explicitly if a condition occurs ie a
specified exception to occur. The statement can be complemented with a
custom exception as well.
Syntax: raise[Exception[,args[,traceback]]]
x = 10
if x > 5:
raise Exception('x should not exceed 5. The value of x
was: {}'.format(x))
The program comes to a halt and displays our exception to screen, offering
clues about what went wrong. Means just to raise exception without handling
it as except block is not there
try:
x=int(input('Enter a number upto 100: '))
if x > 100:
raise ValueError(x)
except ValueError:
print(x, "is out of allowed range")
else:
print(x, "is within the allowed range")
Assertion in Python
assert enables you to verify if a certain condition is met and throw
an exception if it isn’t. It prevents program from crashing. If the
condition is True, then program can continue. If the is False, then
program throw an AssertionError exception.
Syntax: assert expression[,arguments]
num=int(input('Enter a number: '))
assert num>=0
print('You entered: ', num)
The assert statement can optionally include an error message string,
which gets displayed along with the AssertionError.
num=int(input('Enter a number: '))
assert num>=0, "Only positive numbers accepted."
print('You entered: ', num)
The program will come to halt and will not continue.
To continue the error has to be handled by try..except block.
AssertionError
Python assert keyword is defined as a debugging tool that tests a condition. The
AssertionError is also a built-in exception and can be handled using the
try...except construct
try:
num=int(input('Enter a number: '))
assert(num >=0), "Only positive numbers accepted.”
print(num)
except AssertionError as msg:
print(msg)
It is merely a Boolean expression that has a condition or expression checks
if the condition returns true or false. If it is true, the program does not do
anything, and it moves to the next line of code. But if it is false, it raises
an AssertionError exception with an optional error message.
When the input causes an AssertionError, the program will not terminate,
as was the case earlier. Instead, it will be handled by the except block. The
error message in the assert statement will be passed as argument to the
exception argument msg, using keyword as.
as is a keyword that allowsz programmers to name a variable within an
except statement.
Why Assertion is used?
It is a debugging tool, and its primary task is to check the
condition. If it finds that the condition is true, it moves to the next
line of code, and If not, then stops all its operations and throws an
error. It points out the error in the code.
Where Assertion in Python used?
1. Checking the outputs of the functions.
2. Used for testing the code.
3. In checking the values of arguments.
4. Checking the valid input.
If the assertion fails, Python uses ArgumentExpression as the
argument for the AssertionError. AssertionError exceptions can be
caught and handled like any other exception using the try-except
statement, but if not handled, they will terminate the program and
produce a traceback.
User Defined Exceptions
Programmers can name their own exceptions by creating a new exception
class
Exceptions should typically be derived from the Exception class.
When creating a module that can raise several distinct errors, a common
practice is to create a base class for exceptions defined by that module,
and subclass that to create specific exception classes for different error
conditions.
#Custom exceptions
class myError(Exception):
def __init__(self,val):
self.val=val
def __str__(self):
return repr(self.val)
try:
raise myError(10)
except myError as e:
print("User defined exception generated with", e.val)
EXAMPLE 1
#User Defined Exceptions
class Error(Exception): #Base class for other exceptions
pass
class ValueTooSmallError(Error): #Raised when the input value is too small
pass
class ValueTooLargeError(Error): #Raised when the input value is too large
pass
number = 10 # Driver main program
while True:
try:
i_num = int(input("Enter a number: "))
if i_num < number:
raise ValueTooSmallError
elif i_num > number:
raise ValueTooLargeError
break
except ValueTooSmallError:
print("This value is too small, try again!")
print()
except ValueTooLargeError:
DECORATORS
functions are the first class objects, which means that –
Functions are objects; they can be referenced to, passed to a variable
and returned from other functions as well.
Functions can be defined inside another function and can also be
passed as argument to another function.
Decorators allows programmers to modify the behavior of function
or class. Decorators allow us to wrap another function in order to
extend the behavior of wrapped function, without permanently
modifying it.
In Decorators, functions are taken as the argument into another
function and then called inside the wrapper function.
Decorators allow you to make simple modifications to callable
objects like functions, methods, or classes.
a decorator is just another function which takes a functions and
returns one.
Decorators
a decorator takes in a function, adds some functionality and
returns it.
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
ordinary()
pretty = make_pretty(ordinary)
make_pretty() is a decorator. The function ordinary() got decorated
and the returned function was given the name pretty.
The decorator acts as a wrapper. The nature of the object that got
decorated (actual gift inside) does not alter. But now, it looks
pretty (since it got decorated). we decorate a function and reassign
it as, ordinary = make_pretty(ordinary).
Decorators
Python has a syntax to simplify decorator, we can use
the @ symbol along with the name of the decorator function and
place it above the definition of the function to be decorated.
@make_pretty
def ordinary():
print("I am ordinary")
is equivalent to
def ordinary():
print("I am ordinary")
ordinary = make_pretty(ordinary)
print(oridinary())
Reusing Decorators