Search code examples
pythonwith-statementcontextmanager

How to __enter__ n context managers?


Using the with statement, we can enter many context handlers using only one level of indentation/nesting:

>>> from contextlib import contextmanager
>>> @contextmanager
... def frobnicate(n):
...     print('frobbing {}'.format(n))
...     yield
... 
>>> frob1 = frobnicate(1)
>>> frob2 = frobnicate(2)
>>> with frob1, frob2:
...     pass
... 
frobbing 1
frobbing 2

But this doesn't seem to work:

>>> frobs = [frobnicate(1), frobnicate(2)]
>>> with *frobs:
...     pass
# SyntaxError: invalid syntax

How can we enter n context managers without having to manually write out each one?


Solution

  • Python 3.3+ has contextlib.ExitStack:

    from contextlib import ExitStack
    
    with ExitStack() as stack:
        contexts = [stack.enter_context(frobnicate(i)) for i in range(2)]
        ...
    

    See contextlib2 for a backport to older Python versions.