258

假设您通过上下文管理器获取了三个对象,例如锁、数据库连接和 ip 套接字。您可以通过以下方式获取它们:

with lock:
   with db_con:
       with socket:
            #do stuff

但是有没有办法在一个街区内做到这一点?就像是

with lock,db_con,socket:
   #do stuff

此外,是否有可能,给定具有上下文管理器的未知长度的对象数组,是否有可能以某种方式做到:

a=[lock1, lock2, lock3, db_con1, socket, db_con2]
with a as res:
    #now all objects in array are acquired

如果答案是“否”,是因为需要这样的功能意味着糟糕的设计,还是我应该鼓励一下?:-P

4

5 回答 5

449

Python 2.7 和 3.1 及以上版本中,您可以编写:

with A() as X, B() as Y, C() as Z:
    do_something()

这通常是最好的使用方法,但如果您有一个未知长度的上下文管理器列表,您将需要以下方法之一。


Python 3.3中,您可以使用contextlib.ExitStack输入未知长度的上下文管理器列表:

with ExitStack() as stack:
    for mgr in ctx_managers:
        stack.enter_context(mgr)
    # ...

这允许您在将上下文管理器添加到 时创建它们ExitStack,从而防止可能出现的问题contextlib.nested(如下所述)。

contextlib2为 Python 2.6 和 2.7提供了向后移植。ExitStack


Python 2.6 及以下版本中,您可以使用contextlib.nested

from contextlib import nested

with nested(A(), B(), C()) as (X, Y, Z):
    do_something()

相当于:

m1, m2, m3 = A(), B(), C()
with m1 as X:
    with m2 as Y:
        with m3 as Z:
            do_something()

请注意,这与通常使用 nested 并不完全相同with,因为A(),B()C()最初都会在进入上下文管理器之前调用。如果这些函数之一引发异常,这将无法正常工作。

contextlib.nested在较新的 Python 版本中已弃用,以支持上述方法。

于 2010-06-11T18:06:21.737 回答
49

更新:从 python 3.10 开始,您将能够使用带括号的上下文管理器!谢谢@iforapsy!

with (
    mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a,
    mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b,
    mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c,
):
    do_something()

python版本<3.10的原始答案

@interjay 的回答是正确的。但是,如果您需要为长上下文管理器(例如 mock.patch 上下文管理器)执行此操作,那么您很快就会意识到您想要跨行打破这一点。事实证明你不能用括号把它们包起来,所以你必须使用反斜杠。看起来是这样的:

with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \
        mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \
        mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c:
    do_something()
于 2017-09-29T04:45:27.960 回答
32

您问题的第一部分在Python 3.1中是可能的。

对于多个项目,上下文管理器的处理就像嵌套了多个 with 语句一样:

with A() as a, B() as b:
    suite

相当于

with A() as a:
    with B() as b:
        suite

在 3.1 版更改:支持多个上下文表达式

于 2010-06-11T17:42:49.080 回答
11

您问题的第二部分contextlib.ExitStackPython 3.3中得到解决。

于 2013-05-04T19:46:37.137 回答
6

根据@sage88 的回复,您始终可以在输入这些补丁之前为其分配有意义的变量名称。

您可以在多行中创建这些补丁

a_patch = mock.patch('aaaaaaa') 
b_patch = mock.patch('bbbbbbb')
c_patch = mock.patch('ccccccc') 
with a_patch as a, b_patch as b, c_patch as c:    
    do_something()
于 2018-10-19T00:48:15.437 回答