如何__enter__ n上下文管理器?

时间:2014-11-11 00:54:54

标签: python with-statement contextmanager

使用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 上下文管理器而无需手动写出每个上下文管理器?

1 个答案:

答案 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