Please use python's contextlib!
If you ever used python’s magical with
statement, you’ve used the
facilities of contextlib
module. We all know that with
is the
idiomatic way of opening python files. with
saves us the pain of
closing an opened file resource manually. Handling files without using
with
looks like this:
f = open("myfile.txt")
do_something_with_content(f.read())
f.close()
With(!) the help of with
statement, the code is simplified to this:
with open("myfile.txt") as f:
do_something_with_content(f.read())
Although both snippets look similar, with
has an implicit advantage.
In case the do_something_with_content
function raises an exception,
the first snippet will leave the file open, while the second snippet will
close it regardless.
We can make our own contexts/functions to work with with
This is what contextlib
module is made for. For example, say we have a
function prepare_dish
. Every time we call prepare_dish
, it serves
us a prepared food. We need to wash the dishes after consuming the food.
Sometimes we may get interrupted while eating, still we absolutely want to
make sure that the dishes are clean no matter what. Here’s how to implement
a context manager to serve this functionality -
from contextlib import contextmanager
def clean_dishes():
print("Dishes cleaned.")
@contextmanager
def prepare_dish(food):
prepared_food = "cooked {0}".format(food)
try:
# Serve the food to the `with` statement.
yield prepared_food
finally:
# Clean the dishes.
clean_dishes()
# Let's eat some rice!
with prepare_dish("rice") as food:
print("Enjoying '{0}'!".format(food))
Running the above code snippet will output this -
Enjoying 'cooked rice'! Dishes cleaned.
We didn’t ask for it, yet the dishes are cleaned afterwards because of
using a context manager. Because we used try … finally
construct
inside the context manager, our code is also resilient to unexpected
errors. Let’s test this.
with prepare_dish("daal") as food:
raise RuntimeError("Meteor strike imminent!")
The output is:
Dishes cleaned. Traceback (most recent call last): File "context_manager_example.py", line 19, in <module> raise RuntimeError("Meteor strike imminent!") RuntimeError: Meteor strike imminent!
As expected, dishes are cleaned regardless of the RuntimeError
exception.
Seriously, use them!
Context managers can make your python code more beautiful and safe. You can
learn more about contextlib
module from the official documentation at
[python.org](https://docs.python.org/3/library/contextlib.html).