28.7. contextlib — with-statementコンテキストのユーティリティ—Pythonドキュメント
28.7。 contextlib —ユーティリティと -ステートメントコンテキスト
バージョン2.5の新機能。
ソースコード: :source: `Lib / contextlib.py`
このモジュールは、 with ステートメントに関連する一般的なタスクのユーティリティを提供します。 詳細については、コンテキストマネージャータイプおよびステートメントコンテキストマネージャーありも参照してください。
提供される機能:
- contextlib.contextmanager(func)
この関数はデコレータであり、クラスを作成したり、
__enter__()
と__exit__()
メソッド。多くのオブジェクトはwithステートメントでの使用をネイティブにサポートしていますが、それ自体がコンテキストマネージャーではなく、
contextlib.closing
で使用するclose()
メソッドを実装していないリソースを管理する必要がある場合があります。 ]正しいリソース管理を確実にするための抽象的な例は次のとおりです。
from contextlib import contextmanager @contextmanager def managed_resource(*args, **kwds): # Code to acquire resource, e.g.: resource = acquire_resource(*args, **kwds) try: yield resource finally: # Code to release resource, e.g.: release_resource(resource) >>> with managed_resource(timeout=3600) as resource: ... # Resource is released at the end of this block, ... # even if code in the block raises an exception
デコレーションされる関数は、呼び出されたときにジェネレーター-イテレーターを返す必要があります。 このイテレータは、 with ステートメントの as 句のターゲットにバインドされる値を1つだけ生成する必要があります(存在する場合)。
ジェネレーターが降伏する時点で、 with ステートメントにネストされたブロックが実行されます。 ブロックが終了すると、ジェネレータが再開されます。 未処理の例外がブロックで発生した場合、yieldが発生したポイントでジェネレーター内で再発生します。 したがって、 try … except … finally ステートメントを使用して、エラー(存在する場合)をトラップするか、何らかのクリーンアップが行われるようにすることができます。 例外をログに記録するため、または何らかのアクションを実行するために(完全に抑制するのではなく)例外がトラップされた場合、ジェネレーターはその例外を再発生させる必要があります。 それ以外の場合、ジェネレータコンテキストマネージャは with ステートメントに例外が処理されたことを示し、実行は with ステートメントの直後のステートメントから再開されます。
- contextlib.nested(mgr1[, mgr2[, ...]])
複数のコンテキストマネージャーを1つのネストされたコンテキストマネージャーに結合します。
この関数は非推奨になり、 with ステートメントのマルチマネージャー形式が採用されました。
with ステートメントの複数マネージャー形式に対するこの関数の利点の1つは、引数のアンパックにより、次のように可変数のコンテキストマネージャーで使用できることです。
from contextlib import nested with nested(*managers): do_something()
ネストされたコンテキストマネージャーの1つの
__exit__()
メソッドが例外を抑制する必要があることを示している場合、残りの外部コンテキストマネージャーに例外情報が渡されないことに注意してください。 同様に、ネストされたマネージャーの1つの__exit__()
メソッドで例外が発生した場合、以前の例外状態はすべて失われます。 新しい例外は、残りの外部コンテキストマネージャーの__exit__()
メソッドに渡されます。 一般に、__exit__()
メソッドは例外の発生を回避する必要があり、特に、渡された例外を再発生させるべきではありません。この関数には2つの大きな癖があり、非推奨になっています。 まず、関数が呼び出される前にコンテキストマネージャーがすべて構築されるため、内部コンテキストマネージャーの
__new__()
および__init__()
メソッドは、実際には外部コンテキストマネージャーのスコープによってカバーされません。 つまり、たとえば、 nested()を使用して2つのファイルを開くと、プログラミングエラーになります。これは、2番目のファイルを開くときに例外がスローされた場合、最初のファイルがすぐに閉じられないためです。次に、内部コンテキストマネージャーの1つの
__enter__()
メソッドが、外部コンテキストマネージャーの1つの__exit__()
メソッドによってキャッチおよび抑制される例外を発生させる場合、この構成はRuntimeError
。可変数のコンテキストマネージャーのネストをサポートする必要がある開発者は、 warnings モジュールを使用して、この関数によって発生するDeprecationWarningを抑制するか、この関数をアプリケーション固有の実装のモデルとして使用できます。
バージョン2.7以降非推奨: withステートメントはこの機能を直接サポートするようになりました(紛らわしいエラーが発生しやすい癖なしで)。
- contextlib.closing(thing)
ブロックの完了時に thing を閉じるコンテキストマネージャーを返します。 これは基本的に次と同等です。
from contextlib import contextmanager @contextmanager def closing(thing): try: yield thing finally: thing.close()
そして、次のようなコードを書くことができます:
from contextlib import closing import urllib with closing(urllib.urlopen('http://www.python.org')) as page: for line in page: print line
page
を明示的に閉じる必要はありません。 エラーが発生した場合でも、 with ブロックが終了するとpage.close()
が呼び出されます。