Python 将两个上下文管理器合并为一个

Python 将两个上下文管理器合并为一个,python,contextmanager,Python,Contextmanager,我使用Python 2.7,并且我知道我可以编写以下代码: with A() as a, B() as b: do_something() 我想提供一个既方便又方便的助手。此帮助器的用法应如下所示: with AB() as ab: do_something() with multi_context(A, B) as ab: # ... 现在AB()应该同时做两件事:创建上下文A()和创建上下文B() 我不知道如何写这个方便助手不要再发明轮子了;这并不像看上去那么简

我使用Python 2.7,并且我知道我可以编写以下代码:

with A() as a, B() as b:
    do_something()
我想提供一个既方便又方便的助手。此帮助器的用法应如下所示:

with AB() as ab:
    do_something()
with multi_context(A, B) as ab:
    # ...
现在AB()应该同时做两件事:创建上下文A()和创建上下文B()


我不知道如何写这个方便助手

不要再发明轮子了;这并不像看上去那么简单

上下文管理器被视为一个堆栈,并且应该以与输入相反的顺序退出,例如。如果发生异常,此顺序很重要,因为任何上下文管理器都可以抑制异常,此时剩余的管理器甚至不会收到此通知。
\uuuuuu exit\uuuu
方法也可以引发不同的异常,然后其他上下文管理器应该能够处理该新异常。接下来,成功创建
A()
意味着如果
B()
出现异常失败,则应通知它

现在,如果您只想创建预先知道的固定数量的上下文管理器,只需在生成器函数上使用:

from contextlib import contextmanager

@contextmanager
def ab_context():
    with A() as a, B() as b:
        yield (a, b)
然后将其用作:

with ab_context() as ab:
如果您需要处理数量可变的上下文管理器,那么不要构建自己的实现;请改用标准库:

然后,
ExitStack
负责上下文管理器的正确嵌套,以正确的顺序处理退出,并正确传递异常(包括在抑制时不传递异常,以及传递新引发的异常)

如果您觉得这两行(
with
,以及单独调用
enter_context()
)太乏味,可以使用单独的:

然后像这样使用
ab_context

with AB() as ab:
    do_something()
with multi_context(A, B) as ab:
    # ...
对于Python 2,安装,并使用以下导入:

try:
    from contextlib import ExitStack, contextmanager
except ImportError:
    # Python 2
    from contextlib2 import ExitStack, contextmanager
这使您可以避免在Python2上重新发明这个轮子


无论你做什么,都不要使用;这是从Python 3中的库中删除的,理由很充分;它也没有实现正确处理嵌套上下文的进入和退出。

在您的示例中,您没有使用
a
b
ab
——这就提出了一个问题:为什么不使用ab():?@MartinBonner是的,您是对的。在我的例子中,我不需要变量“ab”。马丁·邦纳的回答使用了(a,b),这很好。“这并不像看上去那么简单”——这不是事实吗!