What is a context manager in Python?
A context manager (used with the `with` statement) ensures setup and cleanup code always run, even if an exception occurs - most commonly used for files, locks, and connections.
Python
Overview
The `with` statement guarantees that resources are properly acquired and released. When the block exits - normally or due to an exception - the context manager's cleanup code runs automatically. This eliminates the common bug of forgetting to close a file or release a lock in a `finally` block.
Key Points
- •`with open("file") as f:` automatically calls `f.close()` when the block exits.
- •Context managers implement `__enter__` (setup) and `__exit__` (cleanup) methods.
- •The `as` clause captures the return value of `__enter__`.
- •`contextlib.contextmanager` lets you create one with a generator instead of a class.
- •Multiple managers in one `with`: `with open(a) as f, open(b) as g:`.
Examples
File handling (the classic example)
python# Without context manager - file may not be closed if an error occurs
f = open('data.txt')
try:
data = f.read()
finally:
f.close()
# With context manager - clean and safe
with open('data.txt') as f:
data = f.read()
# f.close() is called automatically, even if f.read() raisesDatabase connection pattern
pythonimport sqlite3
with sqlite3.connect('app.db') as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
# connection closed automatically; transaction committed or rolled backBuild a custom context manager with @contextmanager
pythonfrom contextlib import contextmanager
import time
@contextmanager
def timer(label):
start = time.perf_counter()
try:
yield # code inside the 'with' block runs here
finally:
elapsed = time.perf_counter() - start
print(f"{label}: {elapsed:.4f}s")
with timer("database query"):
results = db.execute("SELECT ...")
# database query: 0.0123sSuppress specific exceptions
pythonfrom contextlib import suppress
# Instead of try/except just to ignore FileNotFoundError:
with suppress(FileNotFoundError):
os.remove('temp.txt') # no error if file doesn't existPro Tip
`with` is not just for files. Use it for threading locks (`with lock:`), temporary directories (`with tempfile.TemporaryDirectory() as tmp:`), database transactions, mocking in tests (`with mock.patch(...)`), and any resource that needs guaranteed cleanup.