Lightweight Context Managers with Python contextlib

Python's built-in contextlib module provides a suite of utilities designed to simplify the creation and management of context managers without requiring boilerplate class definitions. Instead of manually implementing the __enter__() and __exit__() protocol within a custom class, developers can use tools like the @contextmanager decorator and prebuilt helper functions to write clean, lightweight resource-management code using standard generator functions.

The @contextmanager Decorator

The primary tool for creating lightweight context managers is the @contextmanager decorator. It allows a standard generator function to define a context manager. Execution pauses at the yield statement when entering the with block and resumes afterward to handle cleanup.

from contextlib import contextmanager

@contextmanager
def managed_resource():
    # Setup phase (equivalent to __enter__)
    print("Acquiring resource")
    resource = {"status": "active"}
    try:
        yield resource
    finally:
        # Teardown phase (equivalent to __exit__)
        print("Releasing resource")

# Usage
with managed_resource() as res:
    print(f"Using resource: {res['status']}")

Wrapping the yield expression in a try...finally block ensures that cleanup logic always executes, even if an exception occurs inside the with block.

Asynchronous Support: @asynccontextmanager

For asynchronous applications, contextlib provides @asynccontextmanager. It functions identically to @contextmanager but operates on asynchronous generators used alongside async with statements.

from contextlib import asynccontextmanager

@asynccontextmanager
async def async_resource():
    await setup_connection()
    try:
        yield
    finally:
        await close_connection()

Prebuilt Lightweight Context Managers

In addition to custom generator-based context managers, contextlib includes several prebuilt utilities for common resource handling and control flow patterns:

Combining Contexts with ContextDecorator

The ContextDecorator class allows context managers to be used both as standard with statements and as function decorators. Context managers created via @contextmanager automatically inherit from ContextDecorator, allowing a function's entire execution to be encapsulated by the context logic without an extra level of indentation.