If you've ever written with open('file.txt') as f:, you've used a context manager. But what's actually happening under the hood, and why should you care?
The Problem They Solve
Resources like files, network connections, and locks need to be cleaned up after use — even if something goes wrong. Doing this manually is error-prone:
f = open('data.txt')
data = f.read()
f.close() # Never runs if read() throws an exception!
Context managers guarantee cleanup happens, no matter what:
with open('data.txt') as f:
data = f.read()
# file is closed automatically, even on error
How They Work: __enter__ and __exit__
Any object implementing __enter__ and __exit__ can be used with with. Python calls __enter__ when entering the block and __exit__ when leaving it — including when an exception is raised.
class ManagedResource:
def __enter__(self):
print("Acquiring resource")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Releasing resource")
# Return True to suppress the exception, False/None to propagate it
return False
with ManagedResource() as r:
print("Using resource")
Output:
Acquiring resource
Using resource
Releasing resource
The Easier Way: contextlib
Writing a full class for simple cases is overkill. The contextlib module's @contextmanager decorator lets you write a context manager as a generator function:
from contextlib import contextmanager
@contextmanager
def timer(label):
import time
start = time.time()
try:
yield
finally:
print(f"{label}: {time.time() - start:.4f}s")
with timer("database query"):
run_query()
Everything before yield acts as __enter__; everything after (typically in a finally block) acts as __exit__.
Common Real-World Uses
- File I/O:
open()— automatic closing - Locks:
threading.Lock()— automatic release - Database transactions: commit on success, rollback on error
- Temporary state changes: swapping config values and restoring them afterward
- Suppressing exceptions:
contextlib.suppress(FileNotFoundError)
Multiple Context Managers
You can combine several in one with statement:
with open('input.txt') as infile, open('output.txt', 'w') as outfile:
outfile.write(infile.read().upper())
Key Takeaway
Context managers turn "please remember to clean this up" into "this is guaranteed to be cleaned up." Whenever you find yourself writing matching setup/teardown code — especially with try/finally — that's a signal you probably want a context manager instead.
Comments (0)
No comments yet
Be the first to share your thoughts!