Nested Context Managers in Python 2026

Writing Functions Mar 16, 2026

Nested Context Managers in Python 2026

Managing multiple resources (files, database connections, locks, etc.) simultaneously is common in real-world functions. In 2026, using nested context managers correctly is essential for writing safe, clean, and resource-efficient code.

TL;DR — Key Takeaways 2026

  • Use multiple with statements to manage several resources safely
  • Prefer contextlib.ExitStack for dynamic numbers of context managers
  • Nested context managers ensure proper cleanup even if exceptions occur
  • Always handle resources in the correct order (LIFO)

1. Basic Nested Context Managers


# Demo file so this example runs as-is
with open("input.txt", "w") as f:
    f.write("first line\nsecond line\n")

# Simple nested with statements
with open("input.txt", "r") as infile:
    with open("output.txt", "w") as outfile:
        for line in infile:
            outfile.write(line.upper())

2. Cleaner Nested Contexts with ExitStack (Recommended)


from contextlib import ExitStack

def process_multiple_files(file_paths):
    with ExitStack() as stack:
        files = [stack.enter_context(open(path, "r")) for path in file_paths]
        
        # Now safely work with all files
        for f in files:
            content = f.read()
            # process content...

3. Real-World Example with Database and File


from contextlib import ExitStack

async def export_user_data(user_id: int, output_path: str):
    with ExitStack() as stack:
        # Open database session
        db_session = stack.enter_context(get_db_session())
        
        # Open output file
        output_file = stack.enter_context(open(output_path, "w"))
        
        # Both resources are safely managed
        user_data = await db_session.get_user(user_id)
        output_file.write(str(user_data))
        
        # Both will be closed automatically, even if an exception occurs

4. Best Practices for Nested Contexts in 2026

  • Use ExitStack when the number of context managers is dynamic
  • Keep nesting shallow — extract complex logic into separate functions
  • Always use context managers for resources that need cleanup
  • Order matters: resources are cleaned up in reverse order of acquisition
  • Combine with async with for asynchronous context managers

Managing Several Resources at Once

Many tasks need more than one resource, such as an input file and an output file, or a database connection and a lock. You can nest with statements, but Python also allows several managers in one statement, separated by commas. Since Python 3.10 you can put them in parentheses across several lines.

Managers are entered from left to right and exited in reverse order. If entering the second one fails, the first is still closed properly. This ordering matters when one resource depends on another.

When the number of resources is only known at runtime, such as a list of files chosen by the user, contextlib.ExitStack collects them. Every resource registered with enter_context is closed when the stack exits, again in reverse order.

ExitStack also accepts plain callbacks, which is useful for clean-up steps that are not context managers.

Worked Example: Entering and Exiting in Order

We use a small tracing manager to show the order in which nested resources open and close.

from contextlib import contextmanager, ExitStack

@contextmanager
def resource(name):
    print("open", name)
    try:
        yield name
    finally:
        print("close", name)

with (
    resource("input") as src,
    resource("output") as dst,
):
    print("working with", src, "and", dst)

with ExitStack() as stack:
    names = [stack.enter_context(resource(n)) for n in ["a", "b", "c"]]
    print("all open:", names)

The input opens before the output, and the output closes first. With ExitStack, a, b and c open in order and close as c, b, a. The reverse order ensures that a resource is never closed while a later one may still need it.

Practical Tips

Order managers so that each one depends only on those before it, for example a connection before a cursor. The reverse exit order then closes them safely.

When an ExitStack must survive beyond one block, stack.pop_all() moves its resources to a new stack that the caller can close later.

Common Mistakes

  • Deep nesting that pushes the real work far to the right.
  • Opening a dynamic list of files in a loop without ExitStack.
  • Assuming managers close in the order they were opened.
  • Using the parenthesised form on Python versions before 3.10.

Quick Summary

  • Several managers can share one with statement.
  • They exit in reverse order.
  • ExitStack handles a dynamic number of resources.
  • ExitStack also runs plain callbacks.

Conclusion

Nested context managers are a powerful tool for managing multiple resources safely. In 2026, using ExitStack and proper nesting patterns is considered best practice for writing robust, exception-safe functions that handle resources correctly.

Next steps:

  • Review your functions that manage multiple resources and refactor them using ExitStack

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices