Phase 11 of 25 · Topic 11.4

ExitStack & Dynamic Multi-Resource Context Management

1Concept

`contextlib.ExitStack` manages a dynamic or programmatic number of context managers. It unwinds resources safely in LIFO (last-in, first-out) order, preventing resource leaks when opening an arbitrary list of files or locks.

2Architecture Diagram

ExitStack:
  enter_context(File 1) ---> enter_context(File 2) ---> On exit: File 2 closes, then File 1 closes!

3Code Example

Python 3.12
from contextlib import ExitStack
import io

filenames = ["stream_1.txt", "stream_2.txt", "stream_3.txt"]
opened_streams = []

with ExitStack() as stack:
    # Programmatically open arbitrary number of resource buffers
    files = [stack.enter_context(io.StringIO(f"Payload from {name}")) for name in filenames]
    for f in files:
        opened_streams.append(f.read())

print(f"Successfully processed {len(opened_streams)} streams:")
for content in opened_streams:
    print(f" - {content}")

4Expected Output

Successfully processed 3 streams:
 - Payload from stream_1.txt
 - Payload from stream_2.txt
 - Payload from stream_3.txt

5Key Takeaways

  • `ExitStack` solves the problem of opening an unknown number of resources determined at runtime.
  • Resources are exited in reverse order of entry (LIFO).
  • Supports registering arbitrary cleanup callbacks with `stack.callback(func, *args)`.