<p>在<strong>Python 2.7和3.1及更高版本中,您可以编写:</p>
<pre><code>with A() as X, B() as Y, C() as Z:
do_something()
</code></pre>
<p>这通常是最好的方法,但如果您有一个未知长度的上下文管理器列表,您将需要以下方法之一。</p>
<hr/>
<p>在Python 3.3中,可以使用<a href="http://docs.python.org/3/library/contextlib.html#contextlib.ExitStack" rel="noreferrer">contextlib.ExitStack</a>输入上下文管理器的未知长度列表:</p>
<pre><code>with ExitStack() as stack:
for mgr in ctx_managers:
stack.enter_context(mgr)
# ...
</code></pre>
<p>这允许您在将上下文管理器添加到<code>ExitStack</code>时创建上下文管理器,从而防止<code>contextlib.nested</code>(下面提到)可能出现的问题。</p>
<p><a href="https://pypi.python.org/pypi/contextlib2" rel="noreferrer">contextlib2</a>为Python 2.6和2.7提供了<a href="https://contextlib2.readthedocs.io/en/stable/#contextlib2.ExitStack" rel="noreferrer">a backport of ^{<cd1>}</a>。</p>
<hr/>
<p>在<strong>Python 2.6及以下版本中,您可以使用<a href="https://docs.python.org/2/library/contextlib.html#contextlib.nested" rel="noreferrer">^{<cd2>}</a>:</p>
<pre><code>from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
do_something()
</code></pre>
<p>相当于:</p>
<pre><code>m1, m2, m3 = A(), B(), C()
with m1 as X:
with m2 as Y:
with m3 as Z:
do_something()
</code></pre>
<p>注意,这与通常使用嵌套的<code>with</code>并不完全相同,因为<code>A()</code>、<code>B()</code>和<code>C()</code>都将在进入上下文管理器之前首先调用。如果其中一个函数引发异常,则此操作将无法正常工作。</p>
<p><code>contextlib.nested</code>在较新的Python版本中被弃用,取而代之的是上述方法。</p>