複数のコンテキスト マネージャーに「with」ブロックを作成しますか?[重複]
-
26-09-2019 - |
質問
この質問にはすでに答えがあります:
コンテキスト マネージャー経由で取得した 3 つのオブジェクト (ロック、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
解決
で 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
(後述)。
コンテキストライブラリ2 提供します のバックポート 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 バージョンでは非推奨となり、上記のメソッドが優先されます。
他のヒント
あなたの質問の最初の部分は、のPython 3.1 の中で可能です。
ステートメントで複数のネストされたかのように、複数の項目に、コンテキストマネージャが処理されます:
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
でのPython 3.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()