contextlib — with-statementコンテキストのユーティリティ—Pythonドキュメント
contextlib — withステートメントコンテキストのユーティリティ
ソースコード: :source: `Lib / contextlib.py`
このモジュールは、 with ステートメントに関連する一般的なタスクのユーティリティを提供します。 詳細については、コンテキストマネージャータイプおよびステートメントコンテキストマネージャーありも参照してください。
ユーティリティ
提供される関数とクラス:
- class contextlib.AbstractContextManager
object .__ enter __()および object .__ exit __()を実装するクラスの抽象基本クラス。 object .__ enter __()のデフォルトの実装は、
self
を返しますが、 object .__ exit __()は、デフォルトでNone
を返す抽象メソッドです。 ]。 コンテキストマネージャータイプの定義も参照してください。バージョン3.6の新機能。
- class contextlib.AbstractAsyncContextManager
object .__ aenter __()および object .__ aexit __()を実装するクラスの抽象基本クラス。 object .__ aenter __()のデフォルトの実装が提供され、
self
が返されます。一方、 object .__ aexit __()は、デフォルトでNone
を返す抽象メソッドです。 ]。 非同期コンテキストマネージャーの定義も参照してください。バージョン3.7の新機能。
- @contextlib.contextmanager
この関数はデコレータであり、クラスを作成したり、
__enter__()
と__exit__()
メソッド。多くのオブジェクトはwithステートメントでの使用をネイティブにサポートしていますが、それ自体がコンテキストマネージャーではなく、
contextlib.closing
で使用するclose()
メソッドを実装していないリソースを管理する必要がある場合があります。 ]正しいリソース管理を確実にするための抽象的な例は次のとおりです。
デコレーションされる関数は、呼び出されたときにジェネレーター-イテレーターを返す必要があります。 このイテレータは、 with ステートメントの
as
句のターゲットにバインドされる値を1つだけ生成する必要があります(存在する場合)。ジェネレーターが降伏する時点で、 with ステートメントにネストされたブロックが実行されます。 ブロックが終了すると、ジェネレータが再開されます。 未処理の例外がブロックで発生した場合、yieldが発生したポイントでジェネレーター内で再発生します。 したがって、 try … except … finally ステートメントを使用して、エラー(存在する場合)をトラップするか、何らかのクリーンアップが行われるようにすることができます。 例外をログに記録するため、または何らかのアクションを実行するために(完全に抑制するのではなく)例外がトラップされた場合、ジェネレーターはその例外を再発生させる必要があります。 それ以外の場合、ジェネレータコンテキストマネージャは
with
ステートメントに例外が処理されたことを示し、実行はwith
ステートメントの直後のステートメントから再開されます。contextmanager()は ContextDecorator を使用するため、作成するコンテキストマネージャーは with ステートメントと同様にデコレーターとして使用できます。 デコレータとして使用すると、関数呼び出しごとに新しいジェネレータインスタンスが暗黙的に作成されます(これにより、 contextmanager()によって作成された「ワンショット」コンテキストマネージャが、コンテキストマネージャが複数の呼び出しをサポートするという要件を満たすことができます。デコレータとして使用するため)。
バージョン3.2で変更: ContextDecorator の使用。
- @contextlib.asynccontextmanager
contextmanager()に似ていますが、非同期コンテキストマネージャーを作成します。
この関数はデコレータであり、クラスを作成したり、
__aenter__()
と[ X209X] メソッド。 非同期ジェネレーター機能に適用する必要があります。簡単な例:
バージョン3.7の新機能。
- contextlib.closing(thing)
ブロックの完了時に thing を閉じるコンテキストマネージャーを返します。 これは基本的に次と同等です。
そして、次のようなコードを書くことができます:
page
を明示的に閉じる必要はありません。 エラーが発生した場合でも、 with ブロックが終了するとpage.close()
が呼び出されます。
- contextlib.nullcontext(enter_result=None)
__enter__
から enter_result を返すコンテキストマネージャーを返しますが、それ以外は何もしません。 これは、オプションのコンテキストマネージャーの代用として使用することを目的としています。次に例を示します。enter_result を使用した例:
バージョン3.7の新機能。
- contextlib.suppress(*exceptions)
with
ステートメントの本体で発生した場合、指定された例外のいずれかを抑制し、with
ステートメントの終わりに続く最初のステートメントで実行を再開するコンテキストマネージャーを返します。例外を完全に抑制する他のメカニズムと同様に、このコンテキストマネージャーは、プログラムの実行をサイレントに続行することが正しいことがわかっている非常に特定のエラーをカバーするためにのみ使用する必要があります。
例えば:
このコードは次のものと同等です。
このコンテキストマネージャーは再入可能です。
バージョン3.4の新機能。
- contextlib.redirect_stdout(new_target)
sys.stdout を別のファイルまたはファイルのようなオブジェクトに一時的にリダイレクトするためのコンテキストマネージャー。
このツールは、出力がstdoutにハードワイヤードされている既存の関数またはクラスに柔軟性を追加します。
たとえば、 help()の出力は通常、 sys.stdout に送信されます。 出力を io.StringIO オブジェクトにリダイレクトすることにより、その出力を文字列に取り込むことができます。 置換ストリームは
__enter__
メソッドから返されるため、 with ステートメントのターゲットとして使用できます。help()の出力をディスク上のファイルに送信するには、出力を通常のファイルにリダイレクトします。
help()の出力を sys.stderr に送信するには:
sys.stdout のグローバルな副作用は、このコンテキストマネージャーがライブラリコードやほとんどのスレッド化されたアプリケーションでの使用に適していないことを意味することに注意してください。 また、サブプロセスの出力にも影響しません。 ただし、それでも多くのユーティリティスクリプトにとって有用なアプローチです。
このコンテキストマネージャーは再入可能です。
バージョン3.4の新機能。
- contextlib.redirect_stderr(new_target)
redirect_stdout()に似ていますが、 sys.stderr を別のファイルまたはファイルのようなオブジェクトにリダイレクトします。
このコンテキストマネージャーは再入可能です。
バージョン3.5の新機能。
- class contextlib.ContextDecorator
コンテキストマネージャをデコレータとしても使用できるようにする基本クラス。
ContextDecorator
を継承するコンテキストマネージャーは、通常どおり__enter__
と__exit__
を実装する必要があります。__exit__
は、デコレータとして使用されている場合でも、オプションの例外処理を保持します。ContextDecorator
は contextmanager()によって使用されるため、この機能は自動的に取得されます。ContextDecorator
の例:この変更は、次の形式の構成の構文糖衣です。
ContextDecorator
では、代わりに次のように書くことができます。cm
が関数の一部ではなく、関数全体に適用されることを明確にしています(そして、インデントレベルを保存するのも良いことです)。すでに基本クラスを持っている既存のコンテキストマネージャーは、
ContextDecorator
をミックスインクラスとして使用することで拡張できます。ノート
装飾された関数は複数回呼び出すことができる必要があるため、基になるコンテキストマネージャーは複数の with ステートメントでの使用をサポートする必要があります。 そうでない場合は、関数内に明示的な
with
ステートメントを含む元の構成を使用する必要があります。バージョン3.2の新機能。
- class contextlib.ExitStack
他のコンテキストマネージャーとクリーンアップ機能、特にオプションであるか、入力データによって駆動される機能をプログラムで簡単に組み合わせることができるように設計されたコンテキストマネージャー。
たとえば、ファイルのセットは、次のように1つのwithステートメントで簡単に処理できます。
各インスタンスは、インスタンスが閉じられたときに逆の順序で呼び出される登録済みコールバックのスタックを維持します( with ステートメントの最後で明示的または暗黙的に)。 コンテキストスタックインスタンスがガベージコレクションされる場合、コールバックは暗黙的に呼び出されないことに注意してください。
このスタックモデルは、
__init__
メソッドでリソースを取得するコンテキストマネージャー(ファイルオブジェクトなど)を正しく処理できるようにするために使用されます。登録されたコールバックは登録の逆の順序で呼び出されるため、これは、登録されたコールバックのセットで複数のネストされた with ステートメントが使用されたかのように動作します。 これは例外処理にも拡張されます。内部コールバックが例外を抑制または置換する場合、外部コールバックにはその更新された状態に基づいて引数が渡されます。
これは比較的低レベルのAPIであり、出口コールバックのスタックを正しく巻き戻す詳細を処理します。 これは、アプリケーション固有の方法で出口スタックを操作する高レベルのコンテキストマネージャーに適した基盤を提供します。
バージョン3.3の新機能。
- enter_context(cm)
新しいコンテキストマネージャーを入力し、その
__exit__()
メソッドをコールバックスタックに追加します。 戻り値は、コンテキストマネージャー独自の__enter__()
メソッドの結果です。これらのコンテキストマネージャは、 with ステートメントの一部として直接使用される場合と同じように、例外を抑制することができます。
- push(exit)
コンテキストマネージャーの
__exit__()
メソッドをコールバックスタックに追加します。__enter__
はではなく呼び出されるため、このメソッドを使用して、__enter__()
実装の一部をコンテキストマネージャー独自の__exit__()
メソッドでカバーできます。コンテキストマネージャーではないオブジェクトが渡された場合、このメソッドは、それがコンテキストマネージャーの
__exit__()
メソッドと同じ署名を持つコールバックであると見なし、コールバックスタックに直接追加します。これらのコールバックは、true値を返すことにより、コンテキストマネージャー
__exit__()
メソッドと同じ方法で例外を抑制できます。渡されたオブジェクトは関数から返され、このメソッドを関数デコレータとして使用できるようになります。
- callback(callback, /, *args, **kwds)
任意のコールバック関数と引数を受け入れ、それをコールバックスタックに追加します。
他のメソッドとは異なり、この方法で追加されたコールバックは例外を抑制できません(例外の詳細が渡されることはないため)。
渡されたコールバックは関数から返され、このメソッドを関数デコレータとして使用できるようになります。
- pop_all()
コールバックスタックを新しい ExitStack インスタンスに転送し、それを返します。 この操作ではコールバックは呼び出されません。代わりに、新しいスタックが閉じられたときに呼び出されるようになりました( with ステートメントの最後で明示的または暗黙的に)。
たとえば、ファイルのグループは、次のように「オールオアナッシング」操作として開くことができます。
- close()
登録の逆の順序でコールバックを呼び出して、コールバックスタックをすぐに巻き戻します。 登録されているコンテキストマネージャーと終了コールバックの場合、渡された引数は、例外が発生しなかったことを示します。
- class contextlib.AsyncExitStack
非同期コンテキストマネージャーは、 ExitStack と同様で、同期コンテキストマネージャーと非同期コンテキストマネージャーの両方の組み合わせをサポートし、クリーンアップロジックのコルーチンを備えています。
close()
メソッドは実装されていません。代わりに、aclose()
を使用する必要があります。- push_async_exit(exit)
push()
に似ていますが、非同期コンテキストマネージャーまたはコルーチン関数のいずれかが必要です。
- push_async_callback(callback, /, *args, **kwds)
callback()
に似ていますが、コルーチン関数が必要です。
asynccontextmanager()の例を続ける:
バージョン3.7の新機能。
例とレシピ
このセクションでは、 contextlib が提供するツールを効果的に使用するためのいくつかの例とレシピについて説明します。
可変数のコンテキストマネージャーのサポート
ExitStack の主な使用例は、クラスのドキュメントに記載されているものです。単一の with ステートメントで可変数のコンテキストマネージャーとその他のクリーンアップ操作をサポートします。 変動性は、ユーザー入力(ユーザー指定のファイルのコレクションを開くなど)によって駆動される必要のあるコンテキストマネージャーの数、またはオプションのコンテキストマネージャーの一部に起因する場合があります。
示されているように、 ExitStack を使用すると、 with ステートメントを使用して、コンテキスト管理プロトコルをネイティブにサポートしていない任意のリソースを管理することも非常に簡単になります。
__enter__メソッドからの例外のキャッチ
__enter__
メソッド実装からの例外をキャッチすることが望ましい場合があります。なしは、 with ステートメント本体またはコンテキストマネージャーの__exit__
メソッドからの例外を誤ってキャッチします。 。 ExitStack を使用することにより、これを可能にするために、コンテキスト管理プロトコルのステップをわずかに分離することができます。
実際にこれを行う必要があるということは、基盤となるAPIが try / exception / finally ステートメントで使用するための直接リソース管理インターフェースを提供する必要があることを示している可能性がありますがすべてのAPIがその点でうまく設計されているわけではありません。 提供されるリソース管理APIがコンテキストマネージャーのみの場合、 ExitStack を使用すると、 with ステートメントでは直接処理できないさまざまな状況を簡単に処理できます。
__enter__実装でのクリーンアップ
ExitStack.push()のドキュメントに記載されているように、このメソッドは、__enter__()
実装の後のステップが失敗した場合に、すでに割り当てられているリソースをクリーンアップするのに役立ちます。
これは、リソースの取得および解放機能とオプションの検証機能を受け入れ、それらをコンテキスト管理プロトコルにマップするコンテキストマネージャーに対してこれを行う例です。
try-finallyおよびフラグ変数の使用を置き換える
時々見られるパターンは、finally
句の本体を実行する必要があるかどうかを示すフラグ変数を持つtry-finally
ステートメントです。 最も単純な形式(代わりにexcept
句を使用するだけではまだ処理できない)では、次のようになります。
他のtry
ステートメントベースのコードと同様に、セットアップコードとクリーンアップコードはコードの任意の長いセクションで区切られる可能性があるため、これは開発とレビューで問題を引き起こす可能性があります。
ExitStack を使用すると、代わりにwith
ステートメントの最後に実行用のコールバックを登録し、後でそのコールバックの実行をスキップすることができます。
これにより、個別のフラグ変数を必要とせずに、意図したクリーンアップ動作を事前に明示的にすることができます。
特定のアプリケーションがこのパターンを頻繁に使用する場合は、小さなヘルパークラスを使用してさらに単純化できます。
リソースのクリーンアップがスタンドアロン関数にきちんとバンドルされていない場合でも、 ExitStack.callback()のデコレータ形式を使用して、リソースのクリーンアップを事前に宣言することができます。
デコレータプロトコルの動作方法により、この方法で宣言されたコールバック関数はパラメータを受け取ることができません。 代わりに、解放されるすべてのリソースにクロージャー変数としてアクセスする必要があります。
関数デコレータとしてのコンテキストマネージャの使用
ContextDecorator を使用すると、通常のwith
ステートメントと関数デコレータの両方でコンテキストマネージャを使用できます。
たとえば、関数またはステートメントのグループを、開始時刻と終了時刻を追跡できるロガーでラップすると便利な場合があります。 タスクの関数デコレータとコンテキストマネージャの両方を作成するのではなく、 ContextDecorator から継承すると、単一の定義で両方の機能が提供されます。
このクラスのインスタンスは、次の両方のコンテキストマネージャーとして使用できます。
また、関数デコレータとして:
関数デコレータとしてコンテキストマネージャを使用する場合、追加の制限が1つあることに注意してください。__enter__()
の戻り値にアクセスする方法はありません。 その値が必要な場合でも、明示的なwith
ステートメントを使用する必要があります。
使い捨て、再利用可能、再入可能なコンテキストマネージャー
ほとんどのコンテキストマネージャーは、 with ステートメントで一度だけ効果的に使用できるように記述されています。 これらのシングルユースコンテキストマネージャーは、使用するたびに新たに作成する必要があります。2回目に使用しようとすると、例外がトリガーされるか、正しく機能しません。
この一般的な制限は、コンテキストマネージャーを使用する with ステートメントのヘッダーに直接コンテキストマネージャーを作成することをお勧めします(上記のすべての使用例に示されているように)。
最初の with ステートメントはファイルを閉じ、そのファイルオブジェクトを使用したそれ以上のIO操作を防ぐため、ファイルは効果的にシングルユースのコンテキストマネージャーの例です。
contextmanager()を使用して作成されたコンテキストマネージャーもシングルユースのコンテキストマネージャーであり、2回目に使用しようとすると、基になるジェネレーターが生成されないことについて文句を言います。
再入可能なコンテキストマネージャー
より洗練されたコンテキストマネージャーは「再入可能」である可能性があります。 これらのコンテキストマネージャーは、複数の with ステートメントで使用できるだけでなく、同じコンテキストマネージャーを既に使用しているwith
ステートメント内で使用することもできます。
threading.RLock は、 suppress()および redirect_stdout()と同様に、再入可能なコンテキストマネージャーの例です。 リエントラントの使用の非常に簡単な例を次に示します。
再入可能性の実際の例では、複数の関数が相互に呼び出す可能性が高いため、この例よりもはるかに複雑です。
再入可能であることは、スレッドセーフであることと同じではないことにも注意してください。 たとえば、 redirect_stdout()は、 sys.stdout を別のストリームにバインドすることでシステム状態をグローバルに変更するため、スレッドセーフではありません。
再利用可能なコンテキストマネージャー
単一使用と再入可能の両方のコンテキストマネージャーとは異なり、「再利用可能な」コンテキストマネージャーです(または、完全に明示的に言うと、再入可能なコンテキストマネージャーも再利用可能であるため、「再利用可能ですが、再入可能ではありません」コンテキストマネージャーです)。 これらのコンテキストマネージャーは複数回の使用をサポートしていますが、特定のコンテキストマネージャーインスタンスがcontaining withステートメントですでに使用されている場合は失敗します(または正しく機能しません)。
threading.Lock は、再利用可能ですが、再入可能ではないコンテキストマネージャーの例です(再入可能ロックの場合は、代わりに threading.RLock を使用する必要があります)。
再利用可能であるが再入可能ではないコンテキストマネージャーの別の例は、 ExitStack です。これは、コールバックが追加された場所に関係なく、withステートメントを残すときに all 現在登録されているコールバックを呼び出すためです。
例の出力が示すように、複数のwithステートメントで単一のスタックオブジェクトを再利用することは正しく機能しますが、それらをネストしようとすると、最も内側のwithステートメントの最後でスタックがクリアされます。これは望ましい動作ではありません。
単一のインスタンスを再利用する代わりに、個別の ExitStack インスタンスを使用すると、その問題を回避できます。