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() 
Interesting Posts