To improve our craftsmanship as a Python programmer, we need to learn about handling exceptions effectively. One of the tricks to improving our efficiency while handle exceptions is to catch several exceptions using a single except clause.
Python provides us with several ways to catch multiple Exceptions using a single except clause. In this article let us have a look at 3 commonly used ways to do so. Each of these 3 ways are specially suited to be used in 3 specific use-cases/situations. The rest of this articles aims to cover what these 3 ways are and what situations they are best suited for.
If you are a beginner to Python Programming, I recommend reading my other article given below, before reading this one.
In the article above I have explained all the other commonly used tricks/design patterns commonly used while handling exceptions.
Let us start this article by looking at the problem we are trying to solve.
The Problem of Code Repetition with except clauses
Have a look at the code in the example below.
def CodeToHandleExceptions(): # log the errors and do whatever is necessary try: # some problematic code that can produce exceptions except FileNotFoundError: CodeToHandleExceptions() except ValueError: CodeToHandleExceptions() except TypeError: CodeToHandleExceptions() # Rest of the program goes here
As you can see, the 3 exceptions FileNotFoundError, ValueError and TypeError are handled the exact same way using 3 separate except clauses. As you can see the code inside all 3 except clauses are exactly the same.
Code repetition is bad in any programming language and is a maintenance nightmare. If you need to change something in one place that needs to be changed in all 3 places, if we forget one of these places, then we have just introduced a bug into our program.
A good python craftsman should use the features/syntax available effectively to avoid the problems that come with the evil that is code repetition.
Now we have understood the problem we are trying to solve here, the focus of rest of this article will be to learn
- what syntax are available to us to handle multiple exceptions using a single clause and
- which situation is best for using a given syntax variant
Let us start by looking at the 1st syntax and which situation/use-case it is best suited for.
Situation#1: You need to handle a group of specific exceptions the same way
Let us start with a practical example to understand what do I mean by handling a group of specific exceptions the same way
Say your python program wants to download a file from the internet. To do that python provides us with the requests module and this module can raise the following Exceptions if the file cannot be downloaded.
- requests.HTTPError: The server responds by saying the file is not available and sends back some http error codes.
- requests.ConnectTimeout: The connection to the server cannot be made.
If your program needs this file desperately to continue, then no matter which of the above 2 is the actual reason, all you can do at this point is to log the error and exit the program gracefully.
The pseudocode below summarizes the situation above
if TimeoutError or HttpError log the error exit the program
This psuedocode can be translated into python’s try except clauses as follows.
import requests try: url_to_download = 'https://www.embeddedinventor.com' req_obj = requests.get(url_to_download, timeout = 2) # check for http error codes and raise an exception if needed req_obj.raise_for_status() # write the contents to a file open('embeddedinventor.html', 'wb').write(req_obj.content) except (requests.HTTPError, requests.ConnectTimeout) as err: print('Something went wrong, Error Message: ', str(err)) # rest of the program goes here.
Another way of writing the same code is shown below.
exception_tuple = (Error1, Error2, Error3, ....) try: # some code here that can raise many Exceptions except exception_tuple as err: print (str(err))
You can use the above way, if the list of exceptions in your case is very long and you wish to make your code more readable
Hence you can use the syntax mentioned below if your goal is to catch a list/group of specific exceptions and handle them using a single except clause.
try: # some code here that can raise some specific Exceptions except (Error1, Error2, Error3): # code to handle these 3 errors
As you can see on line 4, we can group the Exceptions that need a similar way of handling using a tuple and provide that as the argument to the except clause
Just to refresh your memories, Tuple is a data-structure in Python. In simple terms, tuples can be considered as immutable lists, i.e. once they are declared their contents cannot be changed.
The syntax above assumes 3 errors, but this tuple can be easily extended for more errors if needed.
Situation#2: Handle a given class and its sub-classes of Exceptions the same way
Let us again start with an example, as without an example the concept might look too abstract.
Consider the following situation. Assume you are writing some code that does some cool and very complex mathematics.
If you go to the Python’s official documentation webpage and scroll to the bottom of the page, you can see the Hierarchy tree for built-in exceptions in Python with the BaseException class at the top. All other exception classes are inherited from this BaseException class.
As shown in the above picture, python groups all mathematical exceptions under ArithmeticError and there are 3 built-in exceptions inherited from this ArithmeticError class as listed below.
- OverflowError and
So if you wish to handle all 3 of the above errors under a single except clause you can do so as follows.
try: # some code here that can raise FloatingPointError, OverflowError or ZeroDivisionError except ArithmeticError: # code to handle Exception from these all 3 subclasses
You might ask Couldn’t we have used syntax#1 again in this case?
Yes, you could have used, but say your code needs you to make your own exception which needs to be inherited from ArithmeticError, then this syntax will be more useful to you, as logically for this kind of situation, this is the best syntax to use. In other words, for the reader of your code, this will simply make better sense!
try: # some code here that can raise some specific Exceptions except <Base class name goes here>: # code to handle this class of exception and its subclasses.
Situation#3: Catch and Handle Unforeseen-Exceptions
If you have used C programming Language, you might have noticed that the except clauses in Python are very similar to switch-case statements in C. Just like the fact that the case depends upon the switching variable, the type of Exception decides which except clause will execute.
Also in C’s switch-case we can have a block called default, if variable passed into switch is not matching any of the cases, then default will run.
The python version of default is the except keyword with no arguments next to it, as shown below.
Say you have 10 different exception handlers for each of the 10 possible Exceptions that you think can occur in your program. But what if an unforeseen Exception 11 occurs?
A good practice is to log the error before the interpreter crashes your program. To do so you can use the syntax below.
try: # some code here that can raise some specific Exceptions except Error1: # handle Error1 except Error2: #handle Error2 except Error3: #handle Error3 . . . except Error10: #handle Error10 except: # catch and handle any unforeseen Exceptions
A word of warning, use this syntax wisely. Using this syntax might end up hiding bugs, so make sure you know what you are doing.
This syntax only lets you handle unforeseen exceptions, not log Exception type, so if you know what to do about an unforeseen exception use this syntax. Else, if you wish to log the type of Exception, then I recommend Syntax#4 shown in the next section, which is a variant of Syntax#2.
Bonus Situation: Catch, Log and Handle Unforeseen-Exceptions
except Exception as err: print (str(err))
According to the python documentation
All built-in, non-system-exiting exceptions are derived from this class. All user-defined exceptions should also be derived from this class.
which basically means if you wish to make your own custom exception class, you should inherit from Exception class or one of its subclasses.
As you can see in the image-below, Exception class is the base class of all exceptions which can be raised by a python program.
In Example 6 above, the Exception class is used to catch any unforeseen exceptions and the exception object is assigned to the err object and str(err) prints information about the exception.
If you wish to learn more on how to control what gets printed, I have written a separate article which you can find in the link below.
Let us test this syntax, try running the following code
try: raise TypeError('This is a TypeError.') except Exception as err: print (str(err))
We will get the following output
This is a TypeError.
Here the raise statement is used to manually throw the TypeError. If you wish to learn more about the raise statement and its usage, I have written an article exclusively on the topic of “raise statement” which you can find in the link below
- If you need to handle a group of specific exceptions the same way, use Syntax#1
- If you need to handle a given class and its sub-classes of Exceptions the same way use Syntax#2
- If you need to Catch and Handle Unforeseen-Exceptions use Syntax#3
- If you need to Catch, Log and Handle Unforeseen-Exceptions use Syntax#4.
And with that I will end this article. I hope you enjoyed reading it!
Feel free to share this article with your friends and colleagues!