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.
Here is a video we made about Exceptions and their place in the programming world. I suggest watching the video to get your fundamentals strong before continuing on with this article!
Now that we have a good grasp of the fundamentals, let us get back to the topic and 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
Example: Syntax#1
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.
Syntax#1
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.
Example
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.
- FloatingPointError
- OverflowError and
- ZeroDivisionError
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!
Syntax#2
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.
except:
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.
Syntax
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
exception Exception
https://docs.python.org/
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.
Python Exception Tutorial: Printing Error Messages (5 Examples!)
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
Python: Manually throw/raise an Exception using the “raise” statement
To summarize,
- 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!