While writing programs it is natural to commit error, may it be a spelling mistake, an indentation error or something else. When writing programs, it becomes difficult to quickly get through these errors especially when your code is long enough. At such times, to catch these errors and make your program work properly, every language has a specific mechanism. Similarly, Python also has its ways of preventing and catching error and this mechanism is called exception handling.
So let’s first understand what type of exceptions can be handled by python
What is an Exception?
Any unexpected error that occurs during the execution of the program can be termed as an exception.
Errors
So broadly there are two types of errors:
- Compile-time errors
These errors occur when there is some mistake in the grammar rules of the programming language.
For example any syntax error, if you try to add a string and an integer it will cause an error.
- Run-time errors
These errors occur during the runtime because of unexpected situations.
For example, division by zero is a runtime error.
Common cases of Exceptions
- Division by zero error
- Invalid input
- Accessing the elements of an array beyond its range
- Opening a file which does not exist
- Hard disk crash
- Heap memory exhausted
What is exception handling?
Exception handling is a way of handling exceptions that occur during the runtime of the program and causes the program flow to terminate.
Built-in Python Exceptions
Exception Name | Description |
ZeroDivisionError | Raised when there is division by zero |
EOFError | Raised when the built-in functions input() or raw_input() reaches the end of file (EOF) condition without reading any data. |
IOError | Raised when any input or output operation like opening a file or using print statement fails |
IndexError | Raised when index is out of range |
NameError | Raised when a local or global name is not found. |
ImportError | Raised when import statement fails to find the module to be imported |
TypeError | Raised when the type is inappropriate. For example when we try to calculate the root of a string value, a type error is raised. |
ValueError | Raised when the type is correct but the value is inappropriate. |
OverflowError | Raised when the result of an arithmetic operation is too large to be represented |
KeyError | Raised when the mapping/ dictionary key is not found in the set of existing keys |
Exception Handling in Python
In python, exception handling is done using the try and except clauses.
The code that may generate an error is written in the try block and if the exception is raised then what steps should be done is written in the exception block.
The syntax for the same is
try:
“Code that can cause an exception”
except:
“What to do when the Exception occurs ”
For example
Lets handle the Division by zero error
try:
print “division1 = ”,(4/2)
print “division2 = ”, (4/0)
except:
Print “Division by Zero not possible! Change the denominator value.”
The output of the above code will be –
division1 = 2
division2 = Division by Zero not possible! Change the denominator value.
Let’s take another example where we take an input from the user and try to convert it into integer.
try:
a = input(“Enter your value”)
y = int(a)
except:
print “Invalid input! Enter a numerical value!”
Here if the user enters for example, a string value then it will raise an exception as string cannot be converted into an integer.
Also Read How to convert a list to a string in Python?
Handling Multiple Exceptions
A single program can have different types of errors, so to debug the same it is better to raise a different exception according to the type of error occurred. This can be done by giving multiple exceptions.
Let’s take the case of opening a file and performing some operations on its data.
try:
ufile = open(“abc.txt”)
uread = ufile.readline()
uint = int(s.strip())
val = 201/uint
except IOError:
print “I/O Error!”
except ValueError:
print “unable to convert to integer! Check your input”
except ZeroDivisionError:
print “Division by zero not possible!”
except :
print “unexpected error”
else:
print “ No error!”
The output for the above code is
I/O Error!
Execution Order
First, the try block is executed and if inside it an exception is raised, it will look for a named exception and if not it will execute the unnamed except block.
Now what is named and unnamed except blocks?
The named except: blocks handle the named exceptions for example as we didi above in the case of Multiple exceptions, the ZeroDivisionError, the I/O Error and so on.
While the unnamed except block is the one which handles all the other exceptions i.e. the exceptions not mentioned in the named except blocks, as we did in the above case where at last we gave except: block to handle error other than the mentioned ones, if any.
The finally Block
Finally block is used when you want some part of code which has to execute any how
But in case of try block it may or may not be executed depending on if any error occurred.
The syntax for a finally block will be
try:
“Code that may raise an exception”
except:
“Handle exception here”
finally:
“Code that will always execute”
For example,
try:
Mfile =open(“abc.txt”, “r”)
print Mfile.read()
except:
print “exception occurred!”
finally:
print “Finally done!”
Now looking at the output
If there is an exception, the output would be-
exception occurred!
Finally done!
Now if there is no exception, the output will be-
Finally done!
Raising an Exception
Using the raise keyword, you can force an exception to occur.
You can also pass a custom message to the exception handling module.
Syntax –
raise <exception> [, message]
For example,
Raising a ZeroDivisionError
try:
a = int(raw_input(“numerator”))
b = int(raw_input(“denominator”))
if b == 0:
raise ZeroDivisionError, str(a) + “/0 is not possible”
print a/b
except ZeroDivisionError, e :
print “Exception”, e.message
Note: We are using Python2.7 here, if you are working on python3, there would be a slight change in syntax.
The output for the above code will be-
numerator 2
denominator 0
Exception 2/0 is not possible
Raising a User-defined Exception
The exceptions we talked about till now were all built-in functions. In python, you can also have user-defined exceptions and raise them according to your requirements.
Now, for raising a user-defined exception, you need to define an exception class using the syntax below
class <name of user defined exception> (Exception) :
pass
Then you can create objects to use this exception class
For example,
Class myError (Exception):
pass
Error1 = myError(“Negative input not allowed”)
try:
val = float(raw_input(“Enter value”))
if val < 0:
raise Error1
else:
print “OK”
except myError, e:
print “Error”, e.message
Generators in Python
What is a generator function?
A generator function is a special function that automatically suspends and resumes its execution and state around the point of value generation.
It returns the generated value through the yield statement.
What is a yield statement?
A yield statement suspends the function retaining its current state.
Also, it sends a value to the caller.
The syntax for yield statement is
yield <value>
Now that we understand what are generators, we should also understand how a generator is similar and different from a function.
It is similar because
Generator function uses def statement
It can be invoked
It takes parameters like a function does
But it is also different from a function because
It yields value one at a time instead of generating an array of values.
So to sum up we can say that a generator is like a function in many ways but its behaviour is more like an iterator which returns one value at a time.
So that was all about exception handling and generators in Python. Good Day!