with open("file.txt") as f: is Python’s most common context manager. Understanding how they work under the hood helps you write safer resource-management code and opens the door to understanding how FastAPI’s dependency injection and lifespan events operate.
The Most Common Context Manager
open("students.txt")creates a file object.- Python calls
file.__enter__(), which returns the file object assigned tofile. - The code inside the
withblock executes. - When execution leaves the block (normally or via an exception), Python automatically calls
file.__exit__(), which closes the file.
file.close() — the context manager guarantees it.
How with Works
Any object used with with must implement two special methods:
__enter__()— performs setup; its return value is bound to theasvariable.__exit__(exc_type, exc_value, traceback)— performs cleanup; receives exception info if one occurred.
Creating a Class-Based Context Manager
as receives whatever __enter__() returns.
Generator-Based Context Managers
Writing a full class for simple set-up/tear-down is often unnecessary. Use the@contextmanager decorator from contextlib instead:
Understanding yield
The yield divides the generator into two phases:
- Before
yield— runs when entering thewithblock (setup). - The yielded value — becomes the variable after
as. - After
yield— runs when leaving thewithblock (cleanup).
Exception Handling Inside the Generator
When an exception escapes thewith block, Python does not call next(generator) to resume it normally. Instead it calls generator.throw(exception), injecting the exception back at the point where the generator was paused.
"After Yield" never prints because the exception was injected at the yield, jumping straight to the except block.
Complete Walk-Through
1
Generator is created
generator = my_context() — nothing executes yet.2
Python enters the context
next(generator) runs until yield data. context_data = "my data".3
with block executes
print(context_data) runs, then raise Exception("error").4
Context finally runs
"in context finally" is printed before the exception propagates.5
generator.throw() is called
Python injects the exception back into the generator at the suspended
yield.6
Generator handles the exception
The
except block catches it and prints "from generator: error".7
Generator finally runs
"in generator finally" is always printed.FastAPI Uses the Same Mechanism
FastAPI’syield-based dependencies use exactly this pattern:
Key Takeaways
Summary of context manager rules
Summary of context manager rules
- A context manager performs setup and cleanup automatically.
- The
withstatement works with any object implementing__enter__()and__exit__(). - The variable after
asreceives the return value of__enter__()(or the yielded value for generator-based managers). @contextmanageris the concise way to create custom context managers using a generator function.- Normal completion resumes the generator with
next(generator). - Exceptions resume the generator with
generator.throw(exception). - Code after
yieldonly runs during normal (non-exception) exit. finallyalways runs — making it ideal for guaranteed resource clean-up.- FastAPI
yielddependencies are built on this exact mechanism.