Python context managers are a powerful tool for expressing a common programming pattern in a simple, concise manner. Most commonly they are used to handle opening and closing files, but this is just the beginning of what they can be used for.
Consider the following code snippet, which measures the time it takes to make a list of the first ten thousand square numbers.
We have three steps here; 1) we initialise our timer, 2) we perform some processing and 3) we stop our timer and print the result. We’ll call these three steps enter, process and exit.
The important thing to note here is that the enter and exit steps are codependent. They come as a logical pairing, and it doesn’t make sense to do one without the other.
In this example the enter and exit blocks are physically close to one another, so it is easy to see how they match up, but if we were timing a larger block of code it might not be so obvious. It would be great if we could bundle them together somehow.
Also, we might want to use this same timing pattern in a bunch of places throughout our code. It would be nice if we could put the enter/exit code into something like a function.
The solution is to create a context manager.
In this example
timer() is a function which returns a context manager. The details of how it does this are all taken care of by the
@contextmanager decorator. The key element to notice is that a
yield statement must be placed between the enter and exit code.
To use the context manager we use the
with statement, which is followed by an indented block of code containing the process code.
By factoring the enter/exit code into a context manager function we have created a timing device which can be reused throughout our code. Furthermore, the codependent enter and exit code are kept together, which reduces the likelihood of introducing errors when changes need to be made to the logic.
Finally, the process code is identifiable as a single unit which is “wrapped” by the enter/exit code of the context manager, as it is indented as a block below the
The enter/process/exit pattern is one which shows up in a range of places, and context managers are a neat way to implement this pattern. There are many complex things which can be done with context managers, but these examples show a simple way to get up and running with them to refactor a common, simple pattern.
The examples shown work in Python versions 2.6 and 2.7. Stay tuned for future posts which will go into more details about how to use context managers in more advanced ways.