Context Managers (`with`)
- Use
withstatements to auto-manage resources - Understand what
__enter__and__exit__do - Write your own context managers with
contextlib - Guarantee cleanup even when errors occur
Every open(), requests.Session(), SQLAlchemy session.begin(), and threading.Lock is a context manager. Skipping with blocks is why production servers leak file handles and DB connections. contextlib.contextmanager and ExitStack are quiet superpowers.
- Opening files without
with— on CPython it works via refcount GC, but breaks on PyPy or under exceptions. - Forgetting to
yieldinside a@contextmanagerfunction — thewithblock silently getsNone. - Swallowing exceptions in
__exit__by returning truthy — only returnTruewhen you truly want to suppress.
with thing as x: guarantees that setup runs first and cleanup runs after — even if the block raises.
Classic uses
- File I/O:
with open(path) as f: - Locks, DB transactions, temporary directories
- Timing, profiling, logging blocks
Build your own
@contextmanager on a generator function: code before yield is enter, code after yield is exit.
Try it
- Write a
silenced()context manager that swallows specific exceptions in its block. - Use
timingto comparesum(range(N))vs a manualfor-loop sum.
3 graded exercises
Write the code, click Check. We’ll tell you exactly what to fix.
- Exercise 1
Use
io.StringIOas a context manager to write two lines into it, then print the captured contents. Expected output includes bothhelloandworldon separate lines. - Exercise 2
Use
contextlib.contextmanagerto write atiming(label)context manager that prints"<label>: done"on exit. Then usewith timing("work"):aroundsum(range(100)). Expected output includeswork: done. - Exercise 3
Write a context manager
silenced(*exceptions)(as a class OR via@contextmanager) that swallows any of the given exception types inside its block. Test it with a divide-by-zero insidewith silenced(ZeroDivisionError):, then print"after". Expected:afteris printed and no error surfaces.