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?
A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. with open('/path/to/file.txt', 'r') as f: for line in f: print(line)
What Is the With Statement in Python? In Python, the with statement replaces a try-catch block with a concise shorthand. More importantly, it ensures closing resources right after processing them. A common example of using the with statement is reading or writing to a file.
Python provides an easy way to manage resources: Context Managers. The with keyword is used. When it gets evaluated it should result in an object that performs context management.
contextmanager() uses ContextDecorator so the context managers it creates can be used as decorators as well as in with statements.
You misunderstood that line. The with
statement takes more than one context manager, separated by commas, but not an iterable:
with foo, bar:
works.
Use a contextlib.ExitStack()
object if you need to support a dynamic set of context managers:
from contextlib import ExitStack
with ExitStack() as stack:
for cm in (foo, bar):
stack.enter_context(cm)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With