たとえば、ロック、db接続、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
答えが「いいえ」の場合、そのような機能の必要性が悪い設計を暗示しているからでしょうか、それとも私はそれを一言で提案するべきでしょうか? :-P
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()
_
これは、A()
、B()
、およびC()
がすべて最初に呼び出されるため、ネストされたwith
を通常使用する場合とまったく同じではないことに注意してください。 、コンテキストマネージャに入る前。これらの関数のいずれかが例外を発生させた場合、これは正しく機能しません。
_contextlib.nested
_は、上記のメソッドを支持する新しいバージョンPythonバージョンでは非推奨です。
あなたの質問の最初の部分は Python 3.1 で可能です。
複数のアイテムがある場合、コンテキストマネージャーは複数のwithステートメントがネストされているかのように処理されます。
with A() as a, B() as b: suite
に等しい
with A() as a: with B() as b: suite
バージョン3.1で変更されました:複数のコンテキスト式のサポート
@interjayの答えは正しいです。ただし、長いコンテキストマネージャー(mock.patchコンテキストマネージャーなど)でこれを行う必要がある場合は、これを複数行に分割する必要があることにすぐに気付きます。括弧で囲むことはできないため、バックスラッシュを使用する必要があります。これは次のようなものです。
with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \
mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \
mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c:
do_something()
質問の2番目の部分は、contextlib.ExitStack
in Python 3. 。
@ sage88の応答に続いて、入力する前に、それらのパッチにいつでも意味のある変数名を割り当てることができます。
これらのパッチを複数行で作成できます
a_patch = mock.patch('aaaaaaa')
b_patch = mock.patch('bbbbbbb')
c_patch = mock.patch('ccccccc')
with a_patch as a, b_patch as b, as c:
do_something()