1. ホーム
  2. パイソン

[解決済み】複数のコンテキストマネージャで "with "ブロックを作成する?[重複している]。

2022-04-05 06:02:27

質問

例えば、ロック、データベース接続、IPソケットの3つのオブジェクトをコンテキストマネージャで取得するとします。 これらを取得するには、次のようにします。

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

もし答えが「いいえ」なら、そのような機能の必要性が悪いデザインを意味するからでしょうか? それとも、激励で提案すべきでしょうか?

解決方法は?

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 提供する のバックポートです。 ExitStack Python 2.6 と 2.7 用。


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では非推奨で、上記のメソッドが採用されています。