258

コンテキストマネージャを介して取得する3つのオブジェクト、たとえばAロック、db接続、およびipソケットがあるとします。次の方法で取得できます。

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

しかし、1つのブロックでそれを行う方法はありますか?何かのようなもの

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

、、およびはすべて、コンテキスト マネージャーに入る前に最初に呼び出されるwithため、これはネストされた を通常使用する場合とまったく同じではないことに注意してください。これらの関数のいずれかで例外が発生した場合、これは正しく機能しません。A()B()C()

contextlib.nested上記のメソッドを優先して、新しい Python バージョンでは非推奨です。

于 2010-06-11T18:06:21.737 に答える
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 に答える