Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

Python allows the execution of multiple context managers within a single with statement. This mechanism binds multiple runtime contexts to a single block of code, ensuring that the setup (__enter__) and teardown (__exit__) protocols for all specified objects are managed collectively without requiring deep indentation.

Syntax

Standard Comma-Separated (Python 3.1+) Multiple context managers are separated by commas.
with context_manager_A() as a, context_manager_B() as b:
    # Execution block
Parenthesized Continuation (Python 3.10+) Python 3.10 introduced support for enclosing multiple context managers in parentheses, allowing them to be formatted across multiple lines for PEP 8 compliance.
with (
    context_manager_A() as a,
    context_manager_B() as b,
    context_manager_C() as c
):
    # Execution block
Semantically, declaring multiple context managers in a single with statement is strictly equivalent to nesting them:
with context_manager_A() as a:
    with context_manager_B() as b:
        with context_manager_C() as c:
            # Execution block

Execution Mechanics

The evaluation and execution of multiple context managers follow a strict directional order:
  1. Initialization and __enter__ (Left-to-Right): The context managers are evaluated from left to right. The __enter__() method of the leftmost context manager is invoked first. If an as clause is present, the return value is bound to the target variable. This process repeats sequentially for each subsequent context manager to the right.
  2. __exit__ (Right-to-Left / LIFO): Upon exiting the with block, the __exit__() methods are invoked in Last-In, First-Out (LIFO) order. The rightmost (innermost) context manager’s teardown logic executes first, propagating backwards to the leftmost (outermost) context manager.

Exception Propagation

Handling exceptions across multiple context managers relies on the LIFO teardown sequence and the boolean return value of the __exit__ methods:
  • Exceptions during __enter__: If an exception is raised during the __enter__ phase of the Nth context manager, the __exit__ methods of the 1st through (N-1)th context managers are immediately invoked in reverse order. The Nth context manager’s __exit__ is not called.
  • Exceptions within the block: If an exception occurs inside the with block, the exception type, value, and traceback are passed to the __exit__ method of the rightmost context manager.
    • If the rightmost __exit__ returns False (or None), the exception propagates to the next context manager to the left.
    • If the rightmost __exit__ returns True, the exception is suppressed. The remaining context managers to the left will still have their __exit__ methods called, but they will receive None for the exception arguments, as if the block exited normally.

Dynamic Multiple Context Managers

When the exact number of context managers is unknown at parsing time, Python provides contextlib.ExitStack. This class manages a dynamic stack of context managers, preserving the exact left-to-right setup and right-to-left teardown semantics of a static multiple-context with statement.
from contextlib import ExitStack

managers = [context_manager_A(), context_manager_B(), context_manager_C()]

with ExitStack() as stack:
    # enter_context() pushes the manager onto the stack and returns its __enter__ value
    results = [stack.enter_context(mgr) for mgr in managers]
    
    # Execution block
Master Python with Deep Grasping Methodology!Learn More