In this tutorial, you will master everything about errors and exceptions in python with examples. You will also learn how to raise and assert exceptions. Besides these, you will see the demonstration on the usage of keywords try, except, else, and finally in exception handling.
So far in our series of tutorials, we have come across various types of errors that occur while writing codes. Generally, there exist two distinguishable types of errors in python are: Syntax Errors and Exceptions.
Syntax errors are structural errors caused in python while writing programs.In python for everything is defined in a specific structure called syntax. When this syntax is not fulfilled the parser will detect it as an error. Hence syntax error is also known as parsing error. Take a look at the below example:
print('Hello ,World)
Output Error:
File "exception_ex.py", line 1 print('Hello ,World) ^ SyntaxError: EOL while scanning string literal
In this example, the parser has detected an error and displays the error in the console. Let's see how to scrutinize the error.
Now add the single quote and run it again which gives you the output as Hello, World.
Exceptions are types of errors that occur during the execution of a program even if the program is syntactically correct. This type of error interrupts the normal flow of the program by exhibiting an exception error. See below example showing some of the different types of standard exceptions in python:
In this example, we have encountered 4 types of exception errors namely TypeError
, NameError
, ZeroDivisionError
, and FileNotFoundError
. The error message can be scrutinized as follows:
Unlike syntax errors, exceptions rely on errors that occur due to the failure of logic.
>>> 1+'2'
Output Error:
Traceback (most recent call last): File "", line 1, in 1+'2' TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> 1+two
Output Error:
Traceback (most recent call last): File "", line 1, in 1+two NameError: name 'two' is not defined
>>> 2/0
Output Error:
Traceback (most recent call last): File "", line 1, in 2/0 ZeroDivisionError: division by zero
>>> open('Newfile'
Output Error:
Traceback (most recent call last): File "", line 1, in open('Newfile') FileNotFoundError: [Errno 2] No such file or directory: 'Newfile'
Unlike syntax errors, exceptions rely on errors that occur due to the failure of logic.
Exceptions can be classified into two groups namely
Built-in exceptions are the standard exceptions that are raised when an illegal action takes place in the program. To view all the built-in exception available in python we can use the built-in function local() as given below
print(dir(locals()['__builtins__']))
Where,
(locals()['__builtins__']) returns the exception modules, functions, etc in the system and dir lists them as strings.
Below listed are the built-in exceptions used in python to handle the commonly expected errors while running a program.
Exception | Reason for Exception |
---|---|
AssertionError | Raised when an assert statement fails. |
AttributeError | Raised when attribute assignment or reference fails. |
EOFError | Raised when the input() function hits end-of-file condition. |
FloatingPointError | Raised when a floating-point operation fails. |
GeneratorExit | Raise when a generator's close() method is called. |
ImportError | Raised when the imported module is not found. |
IndexError | Raised when the index of a sequence is out of range. |
KeyError | Raised when a key is not found in a dictionary. |
KeyboardInterrupt | Raised when the user hits the interrupt key (Ctrl+C or Delete). |
MemoryError | Raised when an operation runs out of memory. |
NameError | Raised when a variable is not found in the local or global scope. |
NotImplementedError | Raised by abstract methods. |
OSError | Raised when system operation causes system-related error. |
OverflowError | Raised when the result of an arithmetic operation is too large to be represented. |
ReferenceError | Raised when a weak reference proxy is used to access a garbage collected referent. |
RuntimeError | Raised when an error does not fall under any other category. |
StopIteration | Raised by next() function to indicate that there is no further item to be returned by the iterator. |
SyntaxError | Raised by the parser when a syntax error is encountered. |
IndentationError | Raised when there is incorrect indentation. |
TabError | Raised when indentation consists of inconsistent tabs and spaces. |
SystemError | Raised when the interpreter detects an internal error. |
SystemExit | Raised by sys.exit() function. |
TypeError | Raised when a function or operation is applied to an object of the incorrect type. |
UnboundLocalError | Raised when a reference is made to a local variable in a function or method, but no value has been bound to that variable. |
UnicodeError | Raised when a Unicode-related encoding or decoding error occurs. |
UnicodeEncodeError | Raised when a Unicode-related error occurs during encoding. |
UnicodeDecodeError | Raised when a Unicode-related error occurs during decoding. |
UnicodeTranslateError | Raised when a Unicode-related error occurs during translating. |
ValueError | Raised when a function gets an argument of correct type but improper value. |
ZeroDivisionError | Raised when the second operand of division or modulo operation is zero. |
We can also define our own exceptions which are referred to as user-defined exceptions. We will discuss user-defined exceptions in the upcoming tutorial after mastering the concept of class.
Now we are familiar with built-in exceptions that would arise when a condition fails. It is also possible to throw an exception manually if certain conditions fail. We can use the keyword raise to throw such exceptions. Here is an example:
age= 15
if age<18:
raise Exception('Age must be greater than or equal to 18'
Output Error:
Traceback (most recent call last): File "Exception_ex.py", line 67, inraise Exception('Age must be greater than or equal to 18') Exception: Age must be greater than or equal to 18
We can also specify the type of error to be raised and what information needs to be given to the user.
age=int(input('Enter your age:'))
if age<0:
raise ValueError("Invalid age given as input!")
Output Error:
Enter your age: -2 Traceback (most recent call last): File "Exception_ex.py", line 72, inraise ValueError("Invalid age given as input!") ValueError: Invalid age given as input!
Assert statement is used for debugging. So it tests a condition and checks if the condition is true. If it's true then the program executes normally. But in case, the assert condition fails then the outcome will be an AssertionError exception with an optional error message. See below example:
age = 18
# True Condition
assert age ==18
print(' Age is Valid')
#False condition
assert age ==15
Output Error:
Age is Valid Traceback (most recent call last): File "Exception_ex.py", line 81, inassert age ==15 AssertionError
In the example when the condition evaluates to false the program terminates and produces a traceback out stating assertion error. As done with raise, here too you can define the error as an argument. Observe the following example to understand the change.
age=int(input('Enter your age :'))
assert (age>=18),'Age must be above or equal to 18'
print(' Age is Valid')
Output Error:
Enter your age :15 Traceback (most recent call last): File "Exception_ex.py", line 78, inassert (age>=18),'Age must be above or equal to 18' AssertionError: Age must be above or equal to 18
In a nutshell, we can say that assertion statements, despite handling exceptions, are used as debugging aid. Assertion statement addresses the unrecoverable errors in a program and notifies the developer, which means they are intended to signal for unexpected bugs that would arise in the midway of the program. The program will stop when an assertion error happens and will remain silent till we fix the bug.
Now we can learn how to handle exceptions in python. Both built-in exceptions and user-defined exceptions can be handled using try, except, else and finally statements. While writing code it is always better to use exception statements to avoid any unnecessary error.
To understand the flow of the program during the exception , a basic flowchart is shown below.
If you are suspecting some errors or unusual things amidst execution the best way is to put the block of codes in the “try” statement. The code block after the try statement executes as usual and if it detects any error then the control will rapidly transfer to the “except” statement. The except statement acts as the exception handler catches the error and manages it. In other words, the except statement responds to the exception occurring in the try statement.
Syntax of try…. except block is:
try:
… ….. ….. ...
Run this code
… ….. ….. …
except exception_1:
… ….. ….. ...
Executes on detecting exception_1
… ….. ….. ...
Now we can check out the below examples to understand more on working of try...except block.
try:
fo = open('New.txt','r')
print(fo.read())
fo.close()
except FileNotFoundError:
print('File does not exist in the system!')
In the above example there was no exception and hence executes the program as usual and prints the content it reads in the file. Now consider the case with exception and what will happen.
try:
fo = open('File.txt','r')
print(fo.read())
fo.close()
except FileNotFoundError:
print('File does not exist in the system!')
In this example, File.txt is a file that is not in the system and hence it raised an exception and program flow shifted to an except statement where we have addressed what to be printed while a FileNot FoundError is encountered. Hence prints the user-friendly output.
You can also add as many except statements as you could if you are suspecting multiple exceptions in your critical code placed in the try statement.
Try:
print(2/0)
fo = open('File.txt','r')
print(fo.read())
fo.close()
except ZeroDivisionError:
print('Mathematically,division by zero is not defined!')
except FileNotFoundError:
print('File does not exist in the system!')
From the example, it is pretty clear that the try statement executes till it stumbles on to the first exception.
We can just extend the try..block to the next level by including an optional else clause at the end. This gives clarity on what to execute if the try statement does not have any exceptions. Obviously the try block functions well too if there are no exceptions. The syntax of try ….except ...else takes the form:
try:
… ….. ….. ...
Run this code
… ….. ….. …
except exception_1:
… ….. ….. ...
Executes on detecting exception_1
… ….. ….. ...
else :
… ….. ….. ...
Executes when there is no exception
… ….. ….. ...
Observe the below given example:
try:
print(2/1)
except ZeroDivisionError:
print('Mathematically,division by zero is not defined!')
else:
try:
fo = open('New.txt','r')
print(fo.read())
fo.close()
except FileNotFoundError:
From the output, we can understand that the else part executes here as no exception found in the initial try statement. The interpreter tries to open the file and prints the file content as output since the file exists in the system.
At the end you can add a finally clause to clear up the code after execution. The syntax is :
try:
… ….. ….. ...
Run this code
… ….. ….. …
except exception_1
… ….. ….. ...
Executes on detecting exception_1
… ….. ….. ...
else :
… ….. ….. ...
Executes when there is no exception
… ….. ….. …
finally :
Executes always
Let's see how the ‘finally’ clause is implemented in the program.
#File.txt is not available in system, raises an exception
try:
fo = open('File.txt','r')
print(fo.read())
fo.close()
except FileNotFoundError:
print('File does not exist in the system!')
else:
print('File exist in the system!')
finally:
print('Always executes,irrespective of execution')
Let's change the file name and see what happens when a file is available in the system.
#New.txt is available in system
try:
fo = open('New.txt','r')
print(fo.read())
except FileNotFoundError:
print('File does not exist in the system!')
else:
print('File exist in the system!')
Finally:
fo.close()
print('Always executes,irrespective of execution')
Output:
Hi Welcome To Learn eTutorial File exist in the system! Always executes,irrespective of execution
In the example you may notice that fo.close()
is placed in finally block, this is because finally construct ensures the closure of a file even if we stumble on an exception in between.
What makes the finally
clause special from other statements is that the finally
clause executes always irrespective of execution encountered or not. The finally
clause facilitates the execution of the block of codes that should always run, no matter exceptions detected or not.