Python Context Managers
Guarantee setup and teardown with the with statement and contextlib
Overview
Context managers define what happens when entering and leaving a with block—typically acquiring and releasing resources. Files, locks, and database connections commonly use this pattern to prevent leaks even when errors occur.
Syntax / Usage
# Built-in: files
with open("data.txt") as f:
data = f.read()
# file automatically closed
# Multiple managers
with open("in.txt") as src, open("out.txt", "w") as dst:
dst.write(src.read())
# Custom context manager (class)
class Timer:
def __enter__(self):
import time
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc, tb):
import time
print(f"Elapsed: {time.perf_counter() - self.start:.4f}s")
return False # do not suppress exceptions
with Timer():
sum(range(1_000_000))
# contextlib decorator
from contextlib import contextmanager
@contextmanager
def temporary_env(key, value):
import os
old = os.environ.get(key)
os.environ[key] = value
try:
yield
finally:
if old is None:
del os.environ[key]
else:
os.environ[key] = old
Examples
Database transaction pattern (conceptual):
@contextmanager
def transaction(conn):
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
Suppress errors for optional cleanup:
from contextlib import suppress
with suppress(FileNotFoundError):
Path("temp.cache").unlink()
Common Mistakes
- Returning
Truefrom__exit__and silently swallowing exceptions - Not using context managers for locks, sockets, or DB connections
- Implementing
__enter__without matching cleanup in__exit__
See Also
python-exceptions python-file-io python-decorators