私はこの質問を見て、あなたがいつ を使いたいのか理解していますが、あなたがいつ使いたいwith foo() as bar:
のかわかりません:
bar = foo()
with bar:
....
を使用することによる分解の利点が取り除かれているだけではありませんかwith ... as
、それとも何が起こっているのか誤解していますか? なぜ誰かがただ使いたいのwith
ですか?
@freakishの答えを少し拡張するにwith
は、「コンテキスト」への入り口と出口を保証します。コンテキストとは一体何ですか?まあ、それは「あなたが持っているものは何でも」です。いくつかの明白なものは次のとおりです。
あまり目立たないものには、特定の種類の例外トラップが含まれる場合もあります。ゼロ除算をキャッチし、いくつかの演算を行ってから、キャッチを停止する場合があります。もちろん、これは Python 構文に組み込まれています: try
...except
ブロックとして! 実際、これwith
は単に Python の try/except/finally メカニズムの特殊なケースです (技術的には、try/finally
別のブロックにラップされていtry
ます。コメントを参照してください)。
ブロックのas
一部はwith
、コンテキストエントリがブロック内で使用したい値を提供する場合に役立ちます。ファイルまたはデータベース レコードの場合、新しく開かれたストリームまたは取得したばかりのレコードが必要であることは明らかです。例外をキャッチする場合、またはデータ構造のロックを保持する場合、コンテキスト エントリから値を取得する必要がない場合があります。
たとえば、使用したい場合Lock()
:
from threading import Lock
myLock = Lock()
with myLock:
...
Lock()
オブジェクトは本当に必要ありません。オンになっていることを知っておく必要があります。
with
なしで使用しas
ても、まったく同じティアダウンが得られます。コンテキストを表す新しいローカル オブジェクトが得られないだけです。
これが必要な理由は、コンテキスト自体が直接役に立たない場合があるためです。つまり、コンテキストの開始と終了の副作用のためにのみ使用しているということです。
たとえば、Lock
オブジェクトの場合、ブロックを有効にするには、そのオブジェクトを既に持っているwith
必要があります。したがって、ブロック内でそれが必要になったとしても、それを別の名前に再バインドする理由はありません。コンテキスト マネージャーではないオブジェクトに対してを使用する場合も同様ですcontextlib.closing
。オブジェクト自体は既にあるので、何が返されるかは誰が気にしclosing
ますか?
のようなものsh.sudo
では、使用できるオブジェクトさえありません。
コンテキストマネージャのポイントが、ある状態を隠して自動復元するためだけにある場合もあります。たとえば、-stasher を記述して、ブロック内でtermios.tcsetattr
呼び出すことができます。tty.setraw()
stash オブジェクトがどのように見えるかは気にしません。気にするのは、それが自動復元されることだけです。
decimal.localcontext
これらの方法のいずれかで動作できます — 既に持っているオブジェクトを渡す (したがって、新しい名前は必要ありません)、名前のない一時オブジェクトを渡す、または現在のコンテキストを隠して auto-復元されました。しかし、それらの場合のいずれかで。
コンテキストが必要な場合もあれば、必要でない場合もあります。たとえば、データベース トランザクションを自動コミットするだけの場合with autocommit(db.begin()):
は、ブロック内でアクセスしないため、 と記述できます。ただし、明示的にコミットしない限り自動ロールバックする場合は、おそらく と書くので、ブロック内でwith autorollback(db.begin()) as trans:
実行できます。trans.commit()
(もちろん、PEP 343のtransaction
例のように、通常の終了時にコミットし、例外時にロールバックするトランザクションが実際に必要になることがよくあります。しかし、ここでより良いハイブリッドの例を思いつきませんでした…)
PEP 343とその前身 (PEP 310、PEP 340、および 343 からリンクされたその他のもの) は、これらすべてをある程度説明していますが、何気なく読んだだけでは理解できないことは理解できます。関連性がなく、主にマイルハイトの概要と実装レベルの詳細を説明するだけで、その間のすべてをスキップしています.