Skip to main content

Context Managers

A context manager is an object that performs:
  • Setup before a block of code executes.
  • Cleanup after the block finishes, even if an exception occurs.
It is used with the with statement.
General lifecycle:
Common resources managed using context managers:
  • Files
  • Database connections
  • Locks
  • Network sockets
  • Temporary directories

The Most Common Context Manager

Most Python developers use a context manager without realizing it.
Let’s understand what happens.

Step 1

creates a file object.

Step 2

The returned object is assigned to the variable after as.
Conceptually,
The variable file holds the object returned by open().

Step 3

The code inside the block executes.

Step 4

When execution leaves the with block, Python automatically closes the file.

How Does with Work?

Any object used with the with statement must implement two special methods.
Conceptually,
works like this:
  • __enter__() performs setup.
  • __exit__() performs cleanup.

Creating a Context Manager Using a Class

Usage:
Output:
Notice that the variable after as receives the value returned by __enter__().

Generator-Based Context Managers

Writing a class for simple setup and cleanup is often unnecessary. Python provides the @contextmanager decorator.
Example:
Usage:
Output:

Understanding yield

The yield divides the function into two parts. Before yield
runs before entering the with block. The yielded value
becomes the variable after as.
After the with block finishes, execution resumes after the yield.
Execution flow:

Normal Execution

Example:
Output:
Conceptually, Python behaves like:
Notice that the generator is resumed using:
which continues execution after the yield.

Exception Handling

Now consider this example.
Output:
Notice that:
never executes. Why? Because Python does not resume the generator normally. Instead of:
Python resumes it using:
The exception is injected back into the generator exactly where it was paused. Conceptually,
becomes
Execution flow:

Catching the Exception Inside the Generator

The generator itself can handle the exception.
Output:
Notice that:
is skipped. Since the exception was thrown back into the generator, execution jumps directly to:
instead of continuing after the yield.

Complete Example

The following example demonstrates how an exception raised inside the with block travels back into the generator.
Output:

Step 1

Python creates the generator.
Nothing executes yet.

Step 2

Python enters the context.
Execution pauses at:
The yielded value becomes:

Step 3

The with block executes.
Before leaving the block, the local finally executes.
The exception is still active.

Step 4

Since an exception escaped from the with block, Python does not call:
Instead it calls:
The exception is injected back into the generator at the suspended yield. Conceptually,
becomes
inside the generator.

Step 5

The generator catches the exception.
Output:
Notice that:
never executes because execution does not continue normally after the yield.

Step 6

Finally always executes.
Output:
Since the generator catches the exception and does not re-raise it, the exception is considered handled and no traceback is produced. Execution flow:

FastAPI Uses the Same Mechanism

FastAPI uses generator-based context managers for dependencies.
Execution flow:
The endpoint returning does not immediately send the HTTP response. FastAPI first resumes the generator so that cleanup executes, and only then sends the response to the client.

Key Takeaways

  • A context manager automatically performs setup and cleanup.
  • The with statement works with objects implementing __enter__() and __exit__().
  • The variable after as receives the object returned by __enter__() or yielded by the generator.
  • @contextmanager provides a concise way to create custom context managers.
  • Normal completion resumes the generator using next(generator).
  • Exceptions resume the generator using generator.throw(exception).
  • generator.throw() injects the exception at the suspended yield.
  • Statements after yield execute only during normal execution.
  • finally always executes, making context managers ideal for resource management.
  • FastAPI’s yield dependencies are built on the same mechanism.