Handling multiple exceptions in python

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 when something unexpected happens during the execution of a program. 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.

python exceptions.py 
Enter a number: n
Traceback (most recent call last):
  File "/home/vaati/Desktop/exceptions.py", line 4, in 
    x = int(input("Enter a number: "))
ValueError: invalid literal for int() with base 10: 'n'

From the traceback above, we can see that the user inputs a string n instead of a number, leading to the ValueError. The traceback also shows us the exact location of the error, i.e. line 4, allowing us to go back to the code and fix it.

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.

Handling exceptions allows our programs to continue executing even when errors occur.

Try-Except Clause

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 an invalid input.

If you enter a number which is not an integer, you will get the following output on your terminal.

Please enter a number: n 
The input was not an integer. Please try again...
Please enter a number: 

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.

User-Defined Exceptions

Sometimes, you want to raise exceptions which are not provided by Python. User-defined exceptions give programs more readability. For example, suppose you were designing a part of a program that checks if coupon codes submitted by users are valid. Then you would need to create a custom exception for that purpose.

Custom exceptions inherit from the Python base Exception class as follows.

class CouponError(Exception):
    pass

The exceptions are also defined in a similar way to Python exceptions by ending with Error, though this is optional.

Once the Exception is defined, you can use it in your program as follows.

coupon_list = ['FREEAUG','STUDENT','FREEWEEK']
x = str(input("Enter coupon: "))
if x not in coupon_list:
    raise CouponError
print('coupon is Valid')
   

In the code above, we ask the user for a coupon code, and if the coupon code they provide is not in the coupon_list, a CouponError is raised.

Enter coupon: GT
Traceback (most recent call last):
  File "/home/vaati/Desktop/exceptions.py", line 10, in 
    raise CouponError
__main__.CouponError

To customize the error even more, you can define a more user-friendly message.

class CouponError(Exception):
   def __init__(self, coupon):
       self.coupon = coupon
 
   def __str__(self):
        return  (self.coupon) + ' is an invalid coupon'

Now if you run the program again, the user gets a friendlier error message.

Enter coupon: FREE
Traceback (most recent call last):
  File "/home/vaati/Desktop/exceptions.py", line 15, in 
    raise CouponError(coupon)
__main__.CouponError: FREE is an invalid coupon

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.

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 on the forum.

Learn Python

Learn Python with our complete Python tutorial guide, whether you're just getting started or you're a seasoned coder looking to learn new skills.

This post has been updated with contributions from Esther Vaati. Esther is a software developer and writer for Envato Tuts+.

How do you declare multiple exceptions in Python?

It is possible to define multiple exceptions with the same except clause. It means that if the Python interpreter finds a matching exception, then it'll execute the code written under except clause. Except(Exception1, Exception2,…

What can we do to handle multiple exceptions?

Java Catch Multiple Exceptions A try block can be followed by one or more catch blocks. Each catch block must contain a different exception handler. So, if you have to perform different tasks at the occurrence of different exceptions, use java multi-catch block.

How do you handle multiple exceptions with a single except clause?

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.." ) Finally, you can also leave out the name of the exception after the except keyword.

How many ways can you handle exceptions in Python?

When a Python code throws an exception, it has two options: handle the exception immediately or stop and quit.