It is very common to encounter errors during the execution of a program. Two common kinds of errors that you may have to deal with are syntax errors and exceptions. Syntax errors occur when you type the code incorrectly. In such cases, the erroneous line is repeated by the parser with an arrow pointing to the earliest location where the error was detected.
Exceptions are different from syntax errors. They occur during the execution of a program when something unexpected happens. For example, let’s say you are asking the user to input a number in order to perform a division. Now, if the user enters a string instead of a number and you try to divide a number by the given input, the program will output a TypeError
.
When you are not properly handling exceptions, the program will abruptly quit as it won’t know what to do in such cases. The following code is such an example:
keep_asking = True while keep_asking: x = int(input("Enter a number: ")) print("Dividing 50 by", x,"will give you :", 50/x)
As long as you are entering an integral input value, the program will work correctly. However, as soon as you enter a string or even a decimal number as input, you will get a ValueError
exception.
In this tutorial, you will learn how to properly handle and raise exceptions in Python.
Some Common Exceptions
Here are some basic exceptions that you might encounter when writing programs. You can read about many more built-in exceptions on the official website.
- NameError: This exception is raised when the program cannot find a local or global name. The name that could not be found is included in the error message.
- TypeError: This exception is raised when a function is passed an object of the inappropriate type as its argument. More details about the wrong type are provided in the error message.
- ValueError: This exception occurs when a function argument has the right type but an inappropriate value.
-
NotImplementedError: This exception is raised when an object is supposed to support an operation but it has not been implemented yet. You should not use this error when the given function is not meant to support the type of input argument. In those situations, raising a
TypeError
exception is more appropriate. - ZeroDivisionError: This exception is raised when you provide the second argument for a division or modulo operation as zero.
- FileNotFoundError: This exception is raised when the file or directory that the program requested does not exist.
Just like the names above, most exceptions have self-explanatory names.
Handling an Exception
The code at the beginning of the article asked users to enter an integer as input. If the user did not provide an integer input, the program stopped execution and raised a value error exception. In this section, we will write some code to tell the user that their input is not a valid integer value.
The first step of the process is to include the code that you think might raise an exception inside the try
clause. The next step is to use the except
keyword to handle the exception that occurred in the above code. The modified code for the user input will look like this:
keep_asking = True while keep_asking: try: x = int(input("Please enter a number: ")) print("Dividing 50 by", x,"will give you :", 50/x) except ValueError: print("The input was not an integer. Please try again...")
What happens here is that the program tries to execute the code inside the try
clause. If no exception was raised, the program skips the except
clause and the rest of the code executes normally. If an exception is raised, the program skips the remaining code inside the try
clause and the type of the exception is matched with the name of the exception after the except
keyword. In case of a match, the code inside the except
clause is executed first, and then the rest of the code after the try
clause is executed normally.
When you enter an integer as an input, the program gives you the final result of the division. When a non-integral value is provided, the program prints a message asking you to try and enter an integer again. Note that this time, the program does not abruptly quit when you provide some invalid input.
You can have multiple except
clauses to handle different exceptions. Please keep in mind that these handlers will only deal with exceptions that occurred in the corresponding try
clause. They will not handle any exceptions raised within other exception handlers.
You can also handle multiple exceptions using a single except
clause by passing these exceptions to the clause as a tuple
.
except (ZeroDivisionError, ValueError, TypeError): print("Something has gone wrong..") # code to deal with the exception
Finally, you can also leave out the name of the exception after the except
keyword. This is generally not recommended as the code will now be catching all the exceptions and handling them in the same way. This is not optimal as you will be handling a TypeError
exception the same way as you would have handled a ZeroDivisionError
exception. When handling exceptions, it is better to be as specific as possible and only catch what you can handle.
One possible use of catching all exceptions is to properly print out the exception error on screen like the following code:
import math import sys try: result = math.factorial(2.4) except: print("Something Unexpected has happened.",sys.exc_info()[0]) else: print("The factorial is", result)
Using the Else Clause
You can also use an else
clause in a try ... except
statement. The else
clause is meant to contain code that needs to be executed if the try
clause did not raise any exceptions. This can be useful to make sure that you don’t add any code to the try
block whose exceptions you don’t intend to catch. One thing worth mentioning is that if you decide to use an else
clause, you should include it after all the except
clauses but before the finally
block.
In our case, we could move the line that prints the result of our division inside the else
block.
keep_asking = True while keep_asking: try: x = int(input("Please enter a number: ")) except ValueError: print("The input was not a valid integer. Please try again...") else: print("Dividing 50 by", x,"will give you :", 50/x)
Cleaning Up Using the Finally Clause
Let’s say you have written some code inside the try
block that is supposed to perform a task by utilizing a large amount of resources. It is important to release those resources back when you are done using them. This can be easily achieved by using the finally
clause.
The code inside the finally
clause is always executed irrespective of whether the try
block raised an exception. You can verify this by running the following code:
keep_asking = True while keep_asking: try: x = int(input("Please enter a number: ")) except ValueError: print("The input was not a valid integer. Please try again...") else: print("Dividing 50 by", x,"will give you :", 50/x) finally: print("Already did everything necessary.")
If any of the except
clauses that you specified do not handle the raised exception, the same exception is raised again after the execution of code inside the finally
block.
A More Complex Example
In this section, we will write a program to deal with multiple exceptions. Just like the previous examples, we will be performing some mathematical operations. However, this time we will take the input from a list.
The following code checks for two exceptions, TypeError
and ValueError
. The else
block is used to print the factorial. You can see in the output that this code is executed only when no exception is raised.
import math number_list = [10,-5,1.2,'apple'] for number in number_list: try: number_factorial = math.factorial(number) except TypeError: print("Factorial is not supported for given input type.") except ValueError: print("Factorial only accepts positive integer values.", number," is not a positive integer.") else: print("The factorial of",number,"is", number_factorial) finally: print("Release any resources in use.")
The above code produces the following output:
The factorial of 10 is 3628800 Releasing any resources in use. Factorial only accepts positive integer values. -5 is not a positive integer. Releasing any resources in use. Factorial only accepts positive integer values. 1.2 is not a positive integer. Releasing any resources in use. Factorial is not supported for given input type. Releasing any resources in use.
Another thing worth noticing is that the code inside the finally
clause is executed for each item in the list.
Final Thoughts
I hope this tutorial helped you understand exception handling in Python. Additionally, don’t hesitate to see what we have available for sale and for study in the marketplace, and don’t hesitate to ask any questions and provide your valuable feedback using the feed below.
Properly handling exceptions can be very helpful in situations where exiting a program after it receives an unexpected input is not viable. If you have any questions related to exception handling in Python, please let me know in the comments.