Exception Handling in Python with Examples

It does not matter if you are an experienced programmer. Most definitely, you will find errors while programming. In Python, there are several in-built exceptions. So in this article, we will discuss the errors and exception handling in Python.

If you need a little refresher on Python then check out this cheat sheet for reference:

Errors in Python

There are two types of errors in Python – syntax and logical.

Video tutorials on errors and exception handling in Python are also available from LinkedIn Learning.

Check out this course:

Syntax Error

The syntax error occurs when there is a mistake in the syntax. For example, observe the following code.

x = 10
if x = 10:
	print("Hello World!")

You can go ahead run the code, you will get a syntax error.

Handling syntax error depends on the programmer. The programmer needs to be aware of the syntax properly. Syntax shows after the execution of the code.

Logical Error

Logical errors, commonly known as exceptions occur during the code execution.

Python raises exception when there are problems with the logic of the code or simply when something is wrong with the code.

For example, when a number is divided by 0. Observe the below code:

x = 10
y = x/0

This will raise an error.

y = x/10
ZeroDivisionError: division by zero
>>>

When it comes to logical error or exception, execution starts when a logical error is present in the program.

But as soon as the code encounters it, the program stops.

Exception Handling in Python

It is necessary to handle logical errors or called exceptions. But before discussing how to handle exceptions, let’s go through the sys module briefly.

sys

The sys module provides access to some unique variables and functions that interact with the interpreter. In this article, we need to understand a specific function of the sys module that we will use in the examples.

This function is called sys.exc_info.

The sys.exc_info function returns a tuple that contains some information regarding the exception. It has three values – typevalue, and tracebook.

try and except

The use of try keyword is to handle exception in Python. We write our block of code using the try keyword. 

Along with the try block, you need to use an except block to ensure your program does not stop running. The except block handles the if the code inside the try block fails. 

This code is the earlier example but with try and except blocks. Let’s see what happens now.

As a result of the try and except block, we get no error this time. Only the message in the except block outputting with the type of the exception.

Observe the following code:

import sys

l = [2, 'x', 0, 5, 'abc']


for i in l:
    try:
        x = 10/i
        print("The value of x is: ", x)
    except:
        print("Error occured", sys.exc_info()[0])

Output:

The value of x is: 5.0
Error occured <class 'TypeError'>
Error occured <class 'ZeroDivisionError'>
The value of x is: 2.0 
Error occured <class 'TypeError'>
>>>

Here is how try and except blocks handle every iteration:

First iteration:

i = 2, print statement is executed.

Second iteration:

i = ‘x’, print statement will not execute because there is an exception.

Third iteration:

i = 0, print statement will not execute because the program raises an exception. 

Fourth iteration:

i = 5, print statement will execute.

Fifth iteration:

i = ‘abc’, print statement will not execute because we have an exception.

There are three exceptions here – two ZeroDivisionError and one TypeError

If there is an exception in the try block, Python will not execute the rest of the lines inside that block. 

But we have a problem here. Our program is handling every exception inside one except block. I think it is fine to do that as long you know the reason behind your errors.

But I do not recommend this approach for handling exception in Python.

We should handle each exception separately inside separate exception blocks. 

Let’s work on our previous example, but now we want to handle TypeError and ZeroDivisionError errors differently. 

To handle a specific exception, write the exception name along in the except block.

Here’s the code for that:

import sys

l = [2, 'x', 0, 5, 'abc']


for i in l:
    try:
        x = 10/i
        print("The value of x is: ", x)
    except TypeError:
		print("The type of i is not valid")
    except ZeroDivisionError:
		print("Cannot divide by 0") 

Output:

The value of x is: 5.0
The type of i is not valid
cannot divide by 0
The value of x is: 2.0
The type of i is not valid
>>>

We have a separate message for both TypeError and ZeroDivisionError.

But suppose, we want to handle TypeError and ZeroDivisionError error grouped under one except block, and all other exceptions under another except block. 

As a result, we have to create a single except block for both TypeError and ZeroDivisionError

import sys

l = [2, 'x', 0, 5, 'abc']


for i in l:
    try:
        x = 10/i
        print("The value of x is: ", x)
    except (TypeError, ZeroDivisionError):
		print("TypeError or ZeroDivisionError occurred")
    except:
		print("Any other exception occurred")
```

Output:

The value of x is: 5.0
TypeError or ZeroDivisionError Occured
TypeError or ZeroDivisionError Occured
The value of x is: 2.0
TypeError or ZeroDivisionError Occured
>>>

Both TypeError & ZeroDivisionError raises a single exception.

Using else

In the previous example, we used the print statement inside the try block itself. Well, it works.

but I also don’t recommend doing it that way. 

In the try block, we should only put the critical code, which may raise exceptions. 

The else block comes after the except block, and it executes if there are no exceptions in the try block. 

import sys

l = [2, 'x', 0, 5, 'abc']


for i in l:
    try:
        x = 10/i
    except TypeError:
		print("The type of i is not valid")
    except ZeroDivisionError:
		print("Cannot divide by 0") 
	else:
		print("The value of x is: ", x)

Output:

The value of x is: 5.0
TypeError or ZeroDivisionError Occured
TypeError or ZeroDivisionError Occured
The value of x is: 2.0
TypeError or ZeroDivisionError Occured
>>>

So, if you want to use the print statement, then it is good to use it inside the else block. 

Raising Exceptions Manually

Until now, we discussed how Python raises exceptions at runtime and how we can handle them using try and except.

But we can also raise exceptions manually.

When it comes to handling exception in Python manually, we use the raise keyword. 

Then the name of the exception and pass our message to it.

Here’s how it looks: 

import sys

l1 = [1, 2, 3, 4, 5, 6]
l2 = []

for i in l1:
    try:
        if i % 2 == 0:
            raise ValueError("Even number encountered:", i)
    except ValueError as v:
        print(v)
    else:
        l2.append(i)

print("List with odd numbers: ", l2)

The above code iterates over list “l2”. In the try block, it is checking if the element is even or not. If it is an even number, then we are raising an exception manually. 

And if not, the element is appended to the list l2. So, we are raising the exception using the ValueError

Here is the result:

 ('Even number encountered:', 2)
 ('Even number encountered:', 4)
 ('Even number encountered:', 6)
List with odd numbers: [1,3,5]
>>>

Using finally

The code in the try block executes, and if any error occurs, the except block handles it. 

If no error occurs, then we have the else block. 

We have another optional block that Python executes every time, no matter if there is an error. This block is called the finally block.

import sys

l = [2, 'x', 0, 5, 'abc']


for i in l:
    try:
        x = 10/i
    except TypeError:
        print("The type of i is not valid")
    except ZeroDivisionError:
	print("Cannot divide by 0") 
    else:
	print("The value of x is: ", x)
    finally:
        print("Iteration ends here...")

Output:

The value of x is: 5.0
Iteration ends here...
The type of i is not valid
Iteration ends here...
Cannot divide by 0
Iteration ends here...
The value of x is: 2.0
Iteration ends here...
The type of i is not valid
Iteration ends here...
>>>

The finally block uses a print statement. 

As you can see from the output that Python executes finally block even though there is no error. And also, even when there is an exception. 

In-built exceptions

We have raised three exceptions so far – ValueError, TypeError, and ZeroDivisionError. These exceptions are in-built.

Python raises these in-built exceptions automatically.

Apart from these three, there are several other in-built exceptions in Python.

That’s why, let’s go over them quickly:

  1. IndentationError: Occurs when indentation is not correct.
  2. SystemError: Raised when the system detects an internal error.
  3. IndexError: If the index is out of range.
  4. KeyError: Occurs when the key is not present in the dictionary.
  5. NameError: Raised when Python cannot find the name of the variable.
  6. MemoryError: When memory runs out during operation.
  7. ImportError: If you import a module that does not exist or if Python can’t find it.
  8. AssertionError: This error takes place when an assert statement fails to execute.
  9. OverflowError: Occurs when the arithmetic operation is too long.
  10. UnicodeError: If an error related to Unicode encoding or decoding occurs.

These in-built exceptions are highly critical parts of exception handling in Python.

You may like:

Conclusion

It is essential to know how errors and exception handling in Python work.

Here are some of the points you should keep in mind when it comes to exception handling in Python. 

  • The critical code which may raise error and exceptions should be part of the try block. 
  • Always use different except blocks to handle different types of exceptions. 
  • Don’t add anything else to the try block except the critical code. 

Attach an else block to execute statements if there is no exception in the try block.

Also remember that Python has several in-built exceptions. 

A programmer’s job is to find where the error can occur and place the critical code inside the try block.

The try block also uses an optional else and finally blocks.

And remember that a try block should not be overloaded. That is why Python provides the optional blocks.

To learn more about exception handling in Python check out these courses from LinkedIn Learning:

Also, remember that you can sign up for a LinkedIn Learning account for absolutely free.

Click here for a free account.

Do you find exception handling in Python is easier compared to other programming languages? If so, why?

Leave a Reply