假设您有三个通过上下文管理器获取的对象,例如A锁,数据库连接和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
答案 0 :(得分:281)
在 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提供a backport of 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()
请注意,这与通常使用嵌套的with
不完全相同,因为A()
,B()
和C()
最初都会被调用,然后才会进入情境管理者。如果其中一个函数引发异常,这将无法正常工作。
contextlib.nested
在较新的Python版本中已弃用,支持上述方法。
答案 1 :(得分:22)
问题的第一部分可以在Python 3.1中找到。
如果有多个项目,则会处理上下文管理器,就像多个with语句嵌套一样:
with A() as a, B() as b: suite
相当于
with A() as a: with B() as b: suite
在3.1版中更改:支持多个上下文表达式
答案 2 :(得分:15)
@ interjay的回答是正确的。但是,如果您需要为长期上下文管理器(例如mock.patch上下文管理器)执行此操作,那么您很快就会意识到要跨行分解。事实证明,你不能将它们包裹在parens中,所以你必须使用反斜杠。这是什么样的:
with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \
mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \
mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c:
do_something()
答案 3 :(得分:8)
问题的第二部分通过Python 3.3中的contextlib.ExitStack
解决。
答案 4 :(得分:0)
在@ 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, as c:
do_something()