使用with语句,我们可以只使用一个级别的缩进/嵌套来输入许多上下文处理程序:
>>> 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
但这似乎不起作用:
>>> frobs = [frobnicate(1), frobnicate(2)]
>>> with *frobs:
... pass
# SyntaxError: invalid syntax
我们如何输入 n 上下文管理器而无需手动写出每个上下文管理器?
答案 0 :(得分:6)
python2.7只有contextlib.nested才能做到这一点,但由于容易出错的怪癖而被弃用。
这个函数有两个主要的怪癖,导致它被弃用。首先,由于上下文管理器都是在调用函数之前构造的,因此内部上下文管理器的
__new__()
和__init__()
方法实际上并未涵盖外部上下文管理器的范围。这意味着,例如,使用nested()
打开两个文件是一个编程错误,因为如果在打开第二个文件时抛出异常,第一个文件将不会立即关闭。其次,如果其中一个内部上下文管理器的
__enter__()
方法引发了一个由外部上下文管理器的__exit__()
方法捕获和抑制的异常,则此构造将引发RuntimeError而不是跳过with语句的正文。
python3.3使用contextlib.ExitStack做得更好,如下所示:
from contextlib import ExitStack
with ExitStack() as stack:
contexts = [stack.enter_context(frobnicate(i)) for i in range(2)]
...
有关backport to python2.x代码,请参阅contextlib2。