Context Managers
with statements, __enter__/__exit__, and contextlib
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
s guarantee that setup and teardown happen correctly — even when exceptions are raised.
The with statement:
python with open("file.txt") as f: data = f.read() # f.close() is guaranteed to be called here, even if an exception occurred
How it works — the :protocol[An informal interface — methods a class implements to support a behavior, like __enter__ and __exit__]:
python class ManagedFile: def __init__(self, path): self.path = path def __enter__(self): self.file = open(self.path) return self.file # bound to 'as' variable def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() return False # False = don't suppress exceptions
contextlib.contextmanager — build one with a generator: ``python from contextlib import contextmanager @contextmanager def timer(): import time start = time.perf_counter() yield # code inside 'with' block runs here elapsed = time.perf_counter() - start print(f"Elapsed: {elapsed:.3f}s") with timer(): result = sum(range(1_000_000))
suppress — suppress specific exceptions cleanly: ``python from contextlib import suppress with suppress(FileNotFoundError): os.remove("temp.txt") # doesn't raise if file doesn't exist
Real-world uses: database transactions, locks (threading), temporary directories, mocking in tests, connection pools.
Examples
Database transaction context manager
The most common real-world pattern — guarantees atomicity
from contextlib import contextmanager
@contextmanager
def transaction(conn):
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
with transaction(db_conn) as conn:
conn.execute("INSERT INTO users VALUES (?)", (name,))
conn.execute("INSERT INTO audit_log VALUES (?)", (event,))
# commits if both succeed, rolls back if either raisesTemporary working directory
Combining multiple context managers and finally for guaranteed cleanup
import os
import tempfile
from contextlib import contextmanager
@contextmanager
def temp_directory():
original = os.getcwd()
with tempfile.TemporaryDirectory() as tmpdir:
os.chdir(tmpdir)
try:
yield tmpdir
finally:
os.chdir(original)
with temp_directory() as d:
# work here — directory is deleted on exitHow well did you understand this?
Next in Python Core
functools