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)`.