The with statement
corebeginnerwith obj: runs obj.__enter__() before the block and obj.__exit__() after — even if the block raises. It replaces a manual try/finally for setup and teardown.
Think of it as
with is a promise that cleanup happens no matter what — like a hotel room key that automatically locks the door when you leave, whether you left normally or through the fire exit. You never have to remember to lock it yourself.
What we're doing: Compare a manual try/finally against with for the same open/close guarantee, and confirm the with version closes even though print("opening") and print("closing") never appear out of order.
- 12
- with calls ManagedFile("log.txt").__enter__() first, binding its return value to f.
- 13
- The block runs with f already set up — no separate open() call needed.
- 12–13
- __exit__() runs automatically once the block ends, before the next line of the program.
opening log.txt
using FAKE_HANDLE
closing log.txtWhy this works: "closing log.txt" prints right after the block ends, with no explicit call to close anything — __exit__() ran automatically. A hand-written version would need x = ManagedFile("log.txt"); x.__enter__(); try: ... finally: x.__exit__(...) to get the same guarantee, and every caller would have to remember to write the try/finally correctly.
Doing setup/teardown by hand and forgetting the finally
Wrong
Better
What you see: The file handle is never closed — a resource leak that shows up later as 'too many open files' or a stuck lock, not at the line that caused it.
Why: Calling __enter__()/__exit__() directly means a raise between them skips __exit__() entirely, because nothing is protecting the call with try/finally. with builds that protection in, so a raised exception never bypasses cleanup.
- __enter__() — setup — return value becomes as name
- block body — may complete, or raise
- __exit__() — teardown — always runs
Manual try/finally vs with, for the same guarantee
Together
Remember: with obj as name: runs __enter__ before the block and __exit__ after — even on an exception. It is try/finally you do not have to write.
See also: context manager dunders · contextlib contextmanager · why context managers matter

