python:在几个上下文pipe理器上创build一个“with”块
假设您有三个通过上下文pipe理器获取的对象,例如A锁,一个数据库连接和一个IP套接字。 你可以通过以下方式获得
with lock: with db_con: with socket: #do stuff
但有一种方法可以在一个区块内完成吗? 就像是
with lock,db_con,socket: #do stuff
而且,有可能的话,给定一组具有上下文pipe理器的未知长度的对象,有可能以某种方式进行:
a=[lock1, lock2, lock3, db_con1, socket, db_con2] with a as res: #now all objects in array are acquired
如果答案是“否”,是不是因为需要这样的function意味着devise不好,或者我应该提出一个build议呢? 😛
在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()
请注意,这与通常使用嵌套的不完全相同,因为在进入上下文pipe理器之前, A()
, B()
和C()
都将被初始调用。 如果这些函数中的一个可能引发exception,这将无法正常工作,但将用于问题中的示例。
在Python 2.7和3.1中 ,为此添加了语法,并且已经不赞成使用contextlib.nested
:
with A() as X, B() as Y, C() as Z: do_something()
在Python 3.3中 ,你也可以通过使用contextlib.ExitStack来input未知长度的上下文pipe理器列表:
with ExitStack() as stack: for mgr in ctx_managers: stack.enter_context(mgr) # ...
这允许您创build上下文pipe理器,因为您将它们添加到ExitStack
,从而避免了ExitStack
可能出现的问题。
你的问题的第一部分可能在Python 3.1中 。
对于多个项目,上下文pipe理器将被处理,就好像多个语句是嵌套的一样:
with A() as a, B() as b: suite
相当于
with A() as a: with B() as b: suite
在版本3.1中更改 :支持多个上下文expression式
你的问题的第二部分是用Python 3.3中的 contextlib.ExitStack
解决的。
@ interjay的答案是正确的。 但是,如果您需要为长时间的上下文pipe理器执行此操作,例如mock.patch上下文pipe理器,那么您很快就会意识到您希望跨越这些线程来打破这种情况。 原来,你不能把它们包装在parens中,所以你必须使用反斜杠。 以下是这个样子:
with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \ mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \ mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c: do_something()