Python Errors and Exceptions

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.

Types of errors in Python

Types of errors in Python

What are syntax errors

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.

  • First-line gives the name of the file and line number where the error has been detected.
  • Second-line shows the error statement, in this case, an error is detected at the print function. The “little arrow (^)” at the end of the statement locates the position where the parser ran into a syntax error.
  • The third line gives you the clue about the error. Here it is an EOL missing after the string literal which means we have missed the closing single quote after Hello World.

Now add the single quote and run it again which gives you the output as Hello, World.

What are the exceptions in python?

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. >>> 1+'2'
    
    

    Output Error:

      Traceback (most recent call last):
      File "", line 1, in 
        1+'2'
    
    TypeError: unsupported operand type(s) for +: 'int' and 'str'
    
  2. >>> 1+two
    

    Output Error:

    Traceback (most recent call last):
      File "", line 1, in 
        1+two
    NameError: name 'two' is not defined
    
  3. >>> 2/0
    

    Output Error:

    Traceback (most recent call last):
      File "", line 1, in 
        2/0
    ZeroDivisionError: division by zero
    
  4. >>> open('Newfile' 
    

    Output Error:

    Traceback (most recent call last):
      File "", line 1, in 
        open('Newfile')
    FileNotFoundError: [Errno 2] No such file or directory: 'Newfile'
    

 

  • First-line gives the file name and line number
  • The second-line shows the offending statement
  • The last line specifies the error and its details

 

Unlike syntax errors, exceptions rely on errors that occur due to the failure of logic.

Python built-in exceptions

Exceptions can be classified into two groups namely

  • Built-in Exceptions
  • User-defined Exceptions

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.

How to raise an exception

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:

Example: How to raise an exception

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, in 
    raise 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.

Example: How to raise an exception

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, in 
    raise ValueError("Invalid age given as input!")
ValueError: Invalid age given as input!

How to assert an exception

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:

Example: How to assert an exception

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, in 
    assert 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, in 
    assert (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.

How python handles exceptions

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.

Exception Handling Flowchart

To understand the flow of the program during the exception , a basic flowchart is shown below.

Python Exception Handling Flowchart

Python Exception Handling Flowchart

try...except block

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.

The example shows how the try statement works if there is no exception.

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.

Try...except...else block

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.

Try...finally block

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.