Python exception handling
This article will cover exception handling in python using try-except
block along with use of else
and finally
.
It will explain the use and syntax of all these keywords to handle exceptions in python programs with examples.
What is exception?
During program execution, when an unusual or unexpected condition arises which the program cannot handle, it raises an exception.
Example of unusual conditions include division of a number by 0, opening a file which does not exist, writing to a socket which is closed, accessing an array location beyond its size etc.
Handling an exception means dealing with the unusual conditions so that the application does not exit abnormally.
Exception handling should be performed to make an application stable and user friendly. Exception handling enables an application to show proper error messages and reason of failure.
Applications with proper error handling are reliable and trustworthy.
An exception can be raised due to user’s mistake or a bug in the application itself. Exception handling enables a user to rectify a mistake if it is at his end or report an error if it is from the application end.
Imagine a python program reads a file selected by the user and loads its contents in a window. Now, user selects a file and the application window goes away.
This is because the file he selected did not have read permission and the application blew away. But the user has no clue as to what exactly happened.
An application with exceptions handled properly would show an error message to the user informing him that the selected file does not have read permission so that he can give the permissions or load another file.
Python exception handling support
Exception handling is a vital part of any programming language and is supported by python as well.
Python provides a few keywords which are used to handle exceptions.
They are try
, except
, else
and finally
.
Syntax is:
try:
# risky code
# risky code
except:
# handle error
finally:
# execute always
try
block contains code which might raise an error. This depends on the discretion of the programmer as to which code might raise an error.
If the code raises an error, the control skips and moves to the except
block which contains handling for the error(such as showing error messages or writing them to log file). Then the control moves to finally
block.
Out of the above three keywords, try
is mandatory while except
and finally
are optional but one of these should be present.
That is, a combination of try
–except
, try
–finally
and try
–except
–finally
is permissible. Also, finally
block is always executed, whether there is an exception raised or not.
try
block, lines following the error are not executed and the control moves directly to except
or finally
block.Also, except
keyword could be followed by the specific exception that needs to be handled.
If it is not followed by any exception type, this means that it will handle all exceptions. This approach is not recommended since you will not be able to identify the reason of origin of error.
Remember that in the absence of exception handling, if there is any error raised then it is handled by the runtime environment of the programming language.
Python exception handling example
Following code example will clarify the concept of exception handling in python so that we can dig deeper into it.
try: # read a number from keyboard value = input("Enter a value\n") # divide 100 by the entered value result = 100/int(value) # print result print("Result of division is",result) except ZeroDivisionError: # print error message print("Division by zero") finally: print("Normal program termination")
Above program reads a value from the keyboard, divides 100 by the input value and prints the result. This code might be risky since we do not know the input value.
So, it is embedded inside a try
block followed by an except
block which handles a ZeroDivisionError
.
Thus, if the input value is 0, then the program is equipped to handle it. except
block is followed by a finally
block which will execute irrespective of the value entered.
Sample run of the above program produces the following output.
Enter a value
0
Division by zero
Normal program termination
Output clearly shows that for input value 0, division fails due to which except block is executed followed by finally
block execution.
Note that except
block if followed by an exception will only handle errors that are covered by that exception type.
Thus, catching ZeroDivisionError
will only enable except
block to execute when there is an exception due to division by 0.
Following sample output of above code demonstrates it.
Enter a value
abcd
Traceback (most recent call last):
File “C:/exception.py”, line 5, in <module>
result = 100/int(value)
ValueError: invalid literal for int() with base 10: ‘abcd’
Normal program termination
For the input value abcd
, the program failed with the system generated error.
This is because the program raised a ValueError
but the except block was written to handle ZeroDivisionError
and so it could not catch the other error.
Note that finally
block still executed.
In the above scenario despite adding exception handling, the program failed abnormally. This is because it expected only errors due to division by 0 but ignored invalid input values(such as letters, decimal numbers or special characters etc.).
Fortunately, python provides handling multiple exception types.
There are two ways to handle more than one exception types in a single try block. They are
1. Using multiple except blocks
You may add any number of except
blocks for handling different types of errors for a single try
block.
Only the except
block which matches the type of error will be executed, rest all will be skipped.
Example,
try: # read a number from keyboard value = input("Enter a value\n") # divide 100 by the entered value result = 100/int(value) # print result print("Result of division is",result) except ValueError: # error due to wrong input() print("Invalid value entered") except ZeroDivisionError: # print error message print("Division by zero") except: # handle any other error print("Unexpected error")
Above try
block is followed by 3 except
blocks for handling different error types.
Last except
block is for handling any error apart from ValueError
and ZeroDivisionError
. Sample runs of the program will make it more clear.
Enter a value
0
Division by zero
Enter a value
abcd
Invalid value entered
It is thus understood from the executions that for different error types, appropriate except
blocks are being executed.
2. Multiple exceptions in same except block
It is also possible for a single except
block to handle more than one exception types.
All the exception types are enclosed within parenthesis and separated by a comma and written after except
as shown below.
try: # read a number from keyboard value = input("Enter a value\n") # divide 100 by the entered value result = 100/int(value) # print result print("Result of division is",result) except (ValueError, ZeroDivisionError): # error due to wrong input print("Invalid value or zero entered")
Above except
block will handle input values 0, letters and special characters.
Python try-else block
There are scenarios when you want some code to execute when there was no error raised. For such cases, else
block is used.
This block should be placed after except
block(s) but before finally block. If there is any error, appropriate except
block is executed and if there is no error, then else
block is executed.
In no case, both except
and else
blocks are executed together. Example,
try: # read a number from keyboard value = input("Enter a value\n") # divide 100 by the entered value result = 100/int(value) # print result print("Result of division is",result) except (ValueError, ZeroDivisionError): # error due to wrong input print("Invalid value or zero entered") else: # no error print("Correct value entered")
Output of execution of above code is
Enter a value
10
Result of division is 10.0
Correct value entered
Nested try-except block
You can nest try
–except
block inside another block. There is no limit to the level of nesting. One might ask why such nesting is required.
It might happen that nested block contains some risky code but you want to execute some code which is outside inner block but inside outer block even if there is some error in inner block code execution.
Nesting of try
–except
block becomes handy in such scenarios. Example,
try: value = input("Enter a number") # inner block try: result = 100/int(value) except ZeroDivisionError: print("Division by zero not allowed") # will execute even if there is some error in inner block print("Value entered is",value) except ValueError: print("Error in reading input")
Remember that if there is finally
block with the inner block, then it will be executed before the code after the inner block is executed.
There are times when it becomes necessary to throw or raise an error if some condition is met. This is done when there is no benefit of further execution.
Example, you want to read a file and check for its presence. If the file does not exist, there is no point in moving forward to read the file as this will not succeed. It is better to throw an error in such case.
Python provides
raise
keyword for raising an exception manually. This is followed by the type of error you want to raise. Example,
try: # read a number from keyboard value = input("Enter a value\n") # check for 0 if value == '0': raise ZeroDivisionError # divide 100 by the entered value result = 100/int(value) # print result print("Result of division is",result) except ZeroDivisionError: # error due to wrong input print("Division by zero not allowed")
Above code compares the entered value with ‘0’ and raises a ZeroDivisionError
if it is ‘0’ which is then handled by enclosing except block. Output follows.
Enter a value
0
Division by zero not allowed
Custom exception error messages
You can also provide your own error messages when raising an error and these messages can be accessed inside except
block.
Custom error message should be enclosed inside parenthesis and written after the error is raised.
For accessing the error message, you need to write a variable name preceded with as
keyword after the error being handled in except
block.
An example will clarify it.
try: # read a number from keyboard value = input("Enter a value\n") # check for 0 if value == '0': # raise error with a custom message raise ZeroDivisionError("This will result in error") # divide 100 by the entered value result = 100/int(value) # print result print("Result of division is",result) # associate a variable with the error except ZeroDivisionError as ze: # print custom message print(ze)
Note that when raising an error, a custom message is supplied and when handling the error in except
block, a variable name is supplied preceded with as
keyword.
This variable name is then directly supplied to the print
statement. Above code when executed with an input value of 0 results in the following output.
Enter a number
0
This will result in error
Let’s tweak in
- If a line of code in
try
block results in an error then all the lines following it are skipped. finally
block will always execute, if present.else
block will only execute when there is no error.except
is not executed whenelse
is executed.finally
block can also containtry
–except
block.- Explicit error can also be raised from
finally
block. - Variable name after
as
can be any user defined name. try
–except
block can be nested inside anothertry
–except
block.