How to Use Exceptions in Python : Try, Except, Finally and Raise
Exceptions in Python are a very powerful tool that the vast majority of modern programming languages have. This is a way to control the behaviour of a program when an error occurs.
This is very important since unless we treat this error, the program will stop, and this is something that in certain applications is not a valid option.
Exceptions in Python
Let's imagine that we have the following code with two variables a and b and we perform their division a / b.
a = 4 b = 2 c = a/b
But let's imagine now that for whatever reason the variables have another value, and that for example, if b has the value 0. If we try to divide by zero, this program will give an error and its execution will end abruptly.
a = 4; b = 0 print(a/b) # ZeroDivisionError: division by zero
That "error" that we say has occurred is raised by Python, since the division by zero is an operation that is not mathematically defined.
This is the exception of ZeroDivisionError. In the following link, we have a list of all the exceptions that we can find.
Let's look at an example with another exception. What would happen if we tried to add a number with a text? Obviously this doesn't make any sense, and Python defines an exception for this call TypeError.
print(2 + "2")
Based on this, it is very important to control exceptions, because no matter how many checks we carry out, it is possible that at some point one will occur, and if nothing is done the program will stop.
Can you imagine that on a plane, a train or an ATM you have an error that throws raise an exception and stops completely?
The first approach is to exception handling, it could be done like the following example. We can do a manual check that we are not dividing by zero, in order to avoid having a type error ZeroDivisionError.
However, it is difficult to write code that includes and prevents all kinds of exceptions. To do this, we will see later the use of except.
a = 5 b = 0 # Through this check we prevent it from dividing by zero. if b != 0: print(a/b) else: print("It cannot be divided!")
Use of raise
We can also be the ones to raise or throw an exception. Returning to the examples used in the previous section, we can be the ones to raise
raise. The syntax is very easy.
raise ZeroDivisionError("Exception information")
Or we can launch another of sorts
raise NameError("Exception information")
It can be seen how the one
string we have passed is printed after the exception. It can also be called without any parameters as follows.
Given this, we already know how an exception can be thrown. There are two main ways:
- We do an operation that cannot be performed (such as dividing by zero). In this case Python takes care of automatically throwing the exception.
- Or we can throw an exception manually, using
- There would be a third case that would be to throw an exception that does not belong to those defined by default in Python.
Next, we will see what we can do to handle these exceptions, and what to do when one is thrown so that the execution of the program is not interrupted.
Use of try and except
The good news is that the exceptions we've seen before can be caught and handled properly, without stopping the program. Let's look at an example with division by zero.
a = 5; b = 0 try: c = a / b except ZeroDivisionError: print("Division could not be performed")
In this case, we do not verify that
b != 0. We directly try to perform the division and in the event that the exception is thrown
ZeroDivisionError, we catch it and treat it appropriately.
The difference with the previous example is that now the program does not stop and can continue to run. Try running the code and see what happens. You will see how the program no longer stops.
So what's inside of it
try is the section of code that could throw the exception that is being caught in it
except. Therefore when an exception occurs, it is entered
except but the program does not stop.
You can also catch different exceptions as seen in the following example.
try: c = 5/0 except ZeroDivisionError: print("It cannot be divided by zero!")
try: d = 2 + "Hello" except TypeError: print("Type problem!")
You can also have a certain number of exceptions handled in the same way with the same block of code. However, it is usually more interesting to treat different exceptions differently.
try: c = 2/0 d = 4 + "Wikihtp" except (ZeroDivisionError, TypeError): print("Exception ZeroDivisionError/TypeError")
Another way if you don't know what exception can jump, you can use the generic class Exception. In this case, any type of exception is handled. In fact, all exceptions inherit from Exception. See documentation.
try: d = 4 + "Wikihtp" except Exception: print("There has been an exception")
However, there is a way to know which exception has occurred.
try: d = 2 + "Wiki" except Exception as ex: print("There has been an exception", type(ex))
Its output will be
There has been an exception <class 'TypeError'>
To the already explained
except we can add one more block, that is
else. This block will be executed if no exception has occurred. Please note the difference between the following codes.
try: # We force an exception when dividing by 0 x = 2/0 except: print("Enter except, an exception has occurred") else: print("Enter else, no exception occurred")
The output will be:
Enter except, an exception has occurred
However, in the following code, the division can be done without a problem, so the block is
except not executed but it
else is executed.
try: # Division can be done without problem x = 2/2 except: print("Enter except, an exception has occurred") else: print("Enter else, no exception occurred")
The output will be:
Enter else, no exception occurred
To the already seen blocks
else we can add one more block, that is
finally. This block is always executed, whether or not there has been an exception.
This block is usually used if we want to execute some kind of cleaning action. For example, we are writing data to a file but an exception occurs, we may want to delete the content that we have written previously, so as not to leave inconsistent data in the file.
In the following code, we see an example. Whether or not there is an exception, the code inside
finally will be executed.
try: # We force an exception x = 2/0 except: # It is entered since there has been an exception print("Enter except, an exception has occurred") finally: # It also comes in because finally is always executed print("Enter finally, the finally block is executed")
The output will be;
Enter except, an exception has occurred Enter finally, finally block is executed
A very typical example of exceptions is in file handling. An attempt is made to open, but a possible exception is caught. In fact, if you enter the open documentation, it indicates that it
OSError is launched if the file cannot be opened.
# An attempt is made to open a file and a possible exception is caught try: with open('file.txt') as file: read_data = file.read() except: # It is entered here if it could not be opened print('Could not be opened')
As we have already commented,
except a specific exception can also be caught in it. Depending on our program, we may want to handle different types of exceptions differently, so it is good practice to specify what type of exception we are handling.
# An attempt is made to open a file and a possible exception is caught try: with open('file.txt') as file: read_data = file.read() # We catch a specific exception except OSError: print('OSError. Could not be opened')
In another example we see the use of the blocks try, except, else and finally all together.
try: # Exception force x = 2/0 except: print("Enter except, an exception has occurred") else: print("Enter the else, no exception occurred") finally: print("Enter finally, the finally block is executed")
You can also catch a type exception
SyntaxError, which refers to syntax errors. However, the code should be free of these kinds of bugs, so maybe you should never use this.
try: print("Hello")) except SyntaxError: print("There is a syntax error")