The contextmanager Decorator
Wed 22 January 2020
Table of Contents
Generally, you create a context manager by creating a class with
__exit__methods, but this example shows you how to use the
@contextlib.contextmanagerto create a simple context manager.
Context managers provide a cool programming pattern, especially if you’re forgetful or just have too much to keep track of and you want to simplify your life.
You’ll find them helpful when you have opened something and need to close it, locked something and need to release
it, or changed something and need to reset it. There are several built in context managers that you’re probably
familiar with like
open to open a file or
socket to use a socket. The bog-standard example:
with open('myfile.txt') as f: lines = f.readlines() do_stuff(lines)
open context manager opens a file, returns an object we name as
f. When we’ve done all the
things we’re going to with it,
(we fall out of the
with statement block), the file is automatically closed for us.
In this brief article, you’ll see how you can create a dead-simple context manager from a generator.
Create the Context Manager
First import the
contextlib module. It has several helpers
(read more here: contextlib module).
We’re just going to decorate the
chdir function as a
import contextlib @contextlib.contextmanager def chdir(path): """ On enter, change directory to specified path. On exit, change directory to original. """ this_dir = os.getcwd() os.chdir(path) try: yield finally: os.chdir(this_dir)
To make this work, the function must be a generator and
yield exactly once.
At the point of the
yield, the calling process is executed.
chdir, the function takes a single argument,
- First it makes a note of the current directory and then changes to the
- Then it yields control back to the caller.
- No matter what happens during that process, the function will
finallychange back to the original directory.
Use the Context Manager
Suppose you have some function
gather_paths you want to call for a set of directories.
The following example shows how the
chdir context manager could be used:
with chdir("/mydownloads/wordpress"): gather_paths()
I like this little context manager; it keeps me from having to remember to switch back to the original directory so I don’t get surprised later and find my program is executing somewhere else.
As long as I call the function as a context manager using the
I don’t have to remember to change back to the original directory or do anything special.