Context Managers
Manage setup and cleanup automatically with the with statement.
Syntax
with manager() as value:
...A context manager handles setup and cleanup around a block of code. The with statement you used for files is one — it guarantees the file is closed afterwards.
Writing your own
The simplest way is the contextlib.contextmanager decorator on a generator: code before yield is setup, and code after it is cleanup.
Example
from contextlib import contextmanager
@contextmanager
def tag(name):
print(f'<{name}>')
yield
print(f'</{name}>')
with tag('p'):
print('Hello')
# Output:
# <p>
# Hello
# </p>When to use it
- A database connection is opened inside 'with' to guarantee it is closed even if an exception occurs.
- A temporary directory is created with contextlib.TemporaryDirectory and deleted automatically on exit.
- A threading lock is acquired with 'with lock:' to ensure it is always released when the block exits.
More examples
File context manager
Uses 'with open()' to guarantee the file is closed when the block exits, error or not.
with open('output.txt', 'w') as f:
f.write('Written safely\n')
# File is automatically closed here, even if an error occurs
print('File closed:', f.closed) # TrueCustom context manager with class
Implements __enter__ and __exit__ to create a reusable context manager that times a block.
class Timer:
import time
def __enter__(self):
self.start = __import__('time').perf_counter()
return self
def __exit__(self, *args):
self.elapsed = __import__('time').perf_counter() - self.start
with Timer() as t:
total = sum(range(1_000_000))
print(f'Elapsed: {t.elapsed:.3f}s')contextlib.contextmanager
Uses the @contextmanager decorator to write a generator-based context manager without a class.
from contextlib import contextmanager
@contextmanager
def managed_resource(name):
print(f'Acquiring {name}')
try:
yield name
finally:
print(f'Releasing {name}')
with managed_resource('database connection') as res:
print(f'Using {res}')
# Acquiring database connection
# Using database connection
# Releasing database connection
Discussion