- Bitbucket.org
- Makes use of Bitbucket.org
Context managers in Python are a way of managing resources where we expressly need to do something before and after a block of code, and make sure this is done cleanly. An example is anything to do with I/O, such as writing to a file. First we need to open the file, do some stuff with it and then write to and close the file. This is a pattern where it is easy to forget to close the file, or an exception happens during the write operation in which case resources are not properly unallocated as the file doesn't get closed. Context managers can implicitly abstract this for you.
One of the context managers is the with
keyword. Let's continue with the example of writing to a file.
In the following situation, if there is an exception while writing, the file will not be closed as the f.close()
line will not be reached by the interpreter.
f = open('file.txt', 'w')
f.write("Hello, World!")
f.close()
However in the following code, the file is closed regardless of what happens inside the indented block of code.
with open('file.txt', 'w') as f:
f.write("Hello, World!")
Clearly, the second method is superior.
The behavior of what happens before and after the indented block can be defined by implementing the __enter__
and __exit__
methods (more details can be found in the docs). There is also the contextlib
library which allows you to implement with
support using a decorator and generator-iterator, which would be superior. An example of this is shown below.
Similar to with
, finally
is a block of code that is always run every time in a try...except...finally
code block. This is useful for any cleanup that may need to be done.
We continue with the I/O example from before, so we can use the same Not pythonic code as before.
Here is an example that makes use of both with
and finally
. The example comes from Python Tricks: The Book [5]. This is how we could implement our own with
context manager.
from contextlib import contextmanager
@contextmanager
def managed_file(name):
try:
f = open(name, 'w')
yield f
finally:
f.close()
>>> with managed_file('hello.txt') as f:
f.write('hello, world!')
f.write('bye now')
[1] Python docs -- context managers
[2] Python docs -- contextlib
[3] Python docs -- The try statement
[4] PEP 343 -- The "with" Statement
[5] Python Tricks: A Buffet of Awesome Python Features by Dan Bader
[6] Effective Python: 90 Specific Ways to Write Better Python by Brett Slatkin
[7] Python Cookbook, Third Edition by David Beazley and Brian K. Jones
[8] Writing Idiomatic Python 3 by Jeff Knupp
[9] The Little Book of Python Anti-Patterns by QuantifiedCode