Add `__init__(self, contexts: Iterable[Contextmanager])` to `contextlib.ExitStack`

A quite common use-case for contextlib.ExitStack is to support variable number of contextmanager:

with contextlib.ExitStack() as stack:
    for resource in resources:

However this feel quite verbose. When the output of the __enter__ method is not needed, it would be nice if the above code could be simplified as:

with contextlib.ExitStack(resources):

It is a very minor change but I feel would reduce boilerplate in quite a few common places, like:


See contextlib.nested().

contextlib.nested has documented limitations and is deprecated, so the initial request makes sense.

What would the implementation look like? It would be strange to call enter_context from __init__, so save the managers internally and enter them in __enter__?

The requested feature has exactly the same design flaws as contextlib.nested. It would be unsafe to revive contextlib.nested under other name.


Unless I am misunderstanding something, the proposed feature actually differs from nested in one specific way: it accepts an iterator, which may be lazy.


with nested(*(open(f) for f in files)):


with ExitStack(open(f) for f in files):

The nested version needs to materialize all the items to pass them as arguments, while the ExitStack version can save the lazy iterator and then lazily consume it in its __enter__ method.

Of course, there is still a problem that you could accidentally do something like

with ExitStack([open(f) for f in files]):

resulting in the same incorrect behavior as nested.

Unless we have a way to detect whether the passed iterator is lazy, I am inclined to agree, that this proposal has the same problem as nested.

1 Like