I have a bunch of context managers that I want to chain. On the first glance, contextlib.nested
looked like a fitting solution. However, this method is flagged as deprecated in the documentation which also states that the latest with
statement allows this directly:
Deprecated since version 2.7: The with-statement now supports this functionality directly (without the confusing error prone quirks).
However I could not get Python 3.4.3 to use a dynamic iterable of context managers:
class Foo():
def __enter__(self):
print('entering:', self.name)
return self
def __exit__(self, *_):
pass
def __init__(self, name):
self.name = name
foo = Foo('foo')
bar = Foo('bar')
whether chaining:
from itertools import chain
m = chain([foo], [bar])
with m:
pass
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __exit__
m = [foo, bar]
providing the list directly:
with m:
pass
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __exit__
or unpacking:
with (*m):
pass
File "<stdin>", line 1
SyntaxError: can use starred expression only as assignment target
So, how do I properly chain a dynamic amount of context managers in a with
statement correctly?
You misunderstood that line. The
with
statement takes more than one context manager, separated by commas, but not an iterable:works.
Use a
contextlib.ExitStack()
object if you need to support a dynamic set of context managers: