链接动态可迭代的上下文管理器到单个with语句

时间:2015-06-22 13:50:54

标签: python python-3.x with-statement iterable chain

我有一堆我想链接的上下文管理器。乍一看,contextlib.nested看起来像是一个合适的解决方案。但是,此方法在文档中被标记为已弃用,该文档还声明最新的with语句允许直接使用此方法:

  

自2.7版以来不推荐使用:with语句现在支持此功能   功能直接(没有容易出错的错误)。

但是我无法让Python 3.4.3使用动态可迭代的上下文管理器:

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')

是否链接:

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]

直接提供清单:

with m:
     pass

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __exit__

或拆包:

with (*m):
    pass

  File "<stdin>", line 1
SyntaxError: can use starred expression only as assignment target

那么,如何正确地在with语句中正确链接动态数量的上下文管理器呢?

2 个答案:

答案 0 :(得分:4)

你误解了那条线。 with语句需要多个上下文管理器,用逗号分隔,但不是可迭代:

with foo, bar:

作品。

如果您需要支持动态上下文管理器集,请使用contextlib.ExitStack() object

from contextlib import ExitStack

with ExitStack() as stack:
    for cm in (foo, bar):
        stack.enter_context(cm)

答案 1 :(得分:0)

with语句&#34; 的&#34;多个经理形式,如the statement's documentation所示,将是:

with foo, bar:

即。它不支持支持动态数量的经理。正如the documentation for contextlib.nested所述:

  

需要支持可变数量嵌套的开发人员   上下文管理器可以使用warnings模块来抑制   此函数引发DeprecationWarning或者使用此函数   作为特定于应用程序的实现的模型。