Suppressing Exceptions in Python with contextlib.suppress, not try/except/pass

bowmanjd

Jonathan Bowman

Posted on September 28, 2020

Suppressing Exceptions in Python with contextlib.suppress, not try/except/pass

When programming, it is common to perform an operation that is expected to fail at times, but should not throw an error. In Python, try/except clauses are frequent. In human terms, try/except means, "try this operation, and if it fails for this reason, then do this other thing." For instance, you can try the following out in your console.

friends = {"Nguyen": "tacos", "Hannah": "borscht"}


def get_food(friend_name):
    try:
        food = friends[friend_name]
    except KeyError:
        food = "baklava"
        friends[friend_name] = food
    return food


get_food("Nguyen")
# "tacos"

get_food("Ahmed")
# "baklava"

friends
# {'Nguyen': 'tacos', 'Hannah': 'borscht', 'Ahmed': 'baklava'}
Enter fullscreen mode Exit fullscreen mode

The above in simple language: if the key isn't in the dictionary, don't fret, just add it with a default value.

What if you don't have an alternate course of action? What if you just want to silence the error? Let's say you want to make a directory, and if the directory is already there, don't whine about it, just ignore. Some developers use try/finally for this case as well:

import os

os.mkdir("frivolous_directory")

try:
    os.mkdir("frivolous_directory")
except FileExistsError:
    pass
Enter fullscreen mode Exit fullscreen mode

So, the above works, it is common practice, and one doesn't have to do any special imports. Awesome. No shame if you have good reason to use this pattern.

However, in human terms, the above try/except block reads like this: make the directory, but if that fails because it already exists, then perform the following action: um, nothing.

Crickets

So, from a utility standpoint, it works fine. From a semantic standpoint, it is not particularly meaningful.

A meaningful alternative: contextlib.suppress

If the desire is to simply suppress an error, rather than perform some sort of branching logic, the Python standard library has a paradigm for that: contextlib.suppress(). It works like this:

import contextlib
import os

os.mkdir("frivolous_directory")

with contextlib.suppress(FileExistsError):
    os.mkdir("frivolous_directory")
Enter fullscreen mode Exit fullscreen mode

The FileExistsError in the above was silenced.

This was two less lines of code than the previous try/except example (OK, we had to add import contextlib as well, so one less line in this example).

More importantly, it is very clear what is happening in the code. We don't mind if the operation fails for the specific reason given. There is no pass with unclear intent. We are not trying something nor are we seeking to intercept the error for further logic or processing.

Conclusion

This isn't so much about working code as it is about readable and reasonable code. Using contextlib.suppress is a worthwhile practice. Reading a bit about the treasures in contextlib may be worth your time as well!

💖 💪 🙅 🚩
bowmanjd
Jonathan Bowman

Posted on September 28, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related