Python 3.7+contextlibterm
contextlib.AsyncExitStack
managers
The async counterpart of ExitStack: registers several (async) context managers dynamically and closes them correctly (Python 3.7+).
Syntax
async with contextlib.AsyncExitStack() as stack: ...
Reach for it when the number of resources is only known at runtime: you cannot write one async with for N connections opened in a loop, but a stack accepts them one by one and unwinds them in reverse order on exit. Async managers go in through enter_async_context() and push_async_exit(), while plain sync ones use the same enter_context()/callback() as ExitStack — mixing the two up is the usual mistake. A handy trick is pop_all(), which hands the collected resources to a fresh stack so they survive once setup has fully succeeded.
Examples
import asyncio
import contextlib
print(issubclass(contextlib.AsyncExitStack, contextlib.AbstractAsyncContextManager)) # → True
stack = contextlib.AsyncExitStack()
print(hasattr(stack, 'enter_async_context'), hasattr(stack, 'push_async_callback')) # → True True
print(hasattr(stack, 'enter_context'), hasattr(stack, 'callback')) # → True True
print(hasattr(stack, '__aenter__'), hasattr(stack, '__enter__')) # → True False
print(issubclass(contextlib.AsyncExitStack, contextlib.ExitStack)) # → False
stack.callback(print, 'закрыто')
asyncio.run(stack.aclose()) # → закрыто
See also
Open in the full glossarydocs.python.orgReport an inaccuracy