バージョン 2.5 で追加.
このモジュールは with 構文に関わる一般的なタスクのためのユーティリティを提供します。詳しい情報は、 コンテキストマネージャ型 と with文とコンテキストマネージャ を参照してください。
参考
最新バージョンの contextlib Python source code
提供されている関数:
この関数は with 構文コンテキストマネージャのファクトリ関数を定義するためのデコレータ (decorator) です。新しいクラスを作ったり __enter__() と __exit__() のメソッドを別々にしなくても、ファクトリ関数を定義することができます。
簡単な例(実際にHTMLを生成する方法としてはお勧めできません!)
from contextlib import contextmanager
@contextmanager
def tag(name):
print "<%s>" % name
yield
print "</%s>" % name
>>> with tag("h1"):
... print "foo"
...
<h1>
foo
</h1>
デコレート対象の関数は呼び出されたときにジェネレータ(generator)-イテレータを返す必要があります。このイテレータは値をちょうど一つ yield しなければなりません。 with 構文の as 節が存在するなら、その値は as 節のターゲットへ束縛されることになります。
ジェネレータが yield を実行した箇所で with 文のネストされたブロックが実行されます。ブロックから抜けた後でジェネレータは再開されます。ブロック内で処理されない例外が発生した場合は、ジェネレータ内部の yield を実行した箇所で例外が再送出されます。このように、(もしあれば)エラーを捕捉したり、クリーンアップ処理を確実に実行したりするために、 try...except...finally 構文を使うことができます。例外を捕捉する目的が、(完全に例外を抑制してしまうのではなく)単に例外のログをとるため、もしくはあるアクションを実行するためなら、ジェネレータはその例外を再送出しなければなりません。例外を再送出しない場合、ジェネレータコンテキストマネージャは with 文に対して例外が処理されたことを示し、 with 文の直後の文から実行を再開します。
複数のコンテキストマネージャを一つのネストされたコンテキストマネージャへ結合します。
この関数は、 with 文にマルチマネージャー形式ができたために非推奨になりました。
この関数の with 文のマルチマネージャー形式に対する唯一の利点は、引数のアンパックによって、次の例のように可変数個のコンテキストマネージャーを扱えることです。
with nested(*managers):
do_something()
ネストされたコンテキストマネージャのうちのいずれかの __exit__() メソッドが例外を抑制すべきと判断した場合、外側にある残りのすべてのコンテキストマネージャに例外情報が渡されないということに注意してください。同様に、ネストされたコンテキストマネージャのうちのいずれかの __exit__() メソッドが例外を送出したならば、それ以前の例外状態は失われ、新しい例外が外側にある残りのすべてのコンテキストマネージャの __exit__() メソッドに渡されます。一般的に __exit__() メソッドが例外を送出することは避けるべきであり、特に渡された例外を再送出すべきではありません。
この関数が非推奨になった理由に、2つの大きな問題があります。 1つ目は、全てのコンテキストマネージャーが関数が呼び出される前に構築されることです。内側のコンテキストマネージャーの __new__() と __init__() メソッドは外側のコンテキストマネージャーの内側に入っていません。つまり、例えば nested() を2つのファイルを開くために利用した場合、 2つめのファイルを開くのに失敗すると1つめのファイルが正しく close されないというプログラムエラーになります。
2つ目の問題は、内側のコンテキストマネージャーの1つの __enter__() メソッドが例外を発生させたときに、外側のコンテキストマネージャーの __exit__() メソッドがその例外を捕まえて抑制させてしまうことで、この場合に with の body 部分の実行がスキップされるのではなく RuntimeError が発生する恐れがあります。
可変数個のコンテキストマネージャーのネストをサポートしなければならない場合、 warnings モジュールを利用してこの関数が発生させる DeprecationWarning を抑制するか、この関数を参考にしてアプリケーション独自の実装をすることができます。
バージョン 2.7 で撤廃: with 文がこの関数の機能を(この関数と違って奇妙なエラーを発生させることなしに) 直接サポートしました。
ブロックの完了時に thing を close するコンテキストマネージャを返します。これは基本的に以下と等価です
from contextlib import contextmanager
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
そして、明示的に page を close する必要なしに、このように書くことができます:
from contextlib import closing
import urllib
with closing(urllib.urlopen('http://www.python.org')) as page:
for line in page:
print line
たとえエラーが発生したとしても、 with ブロックを出るときに page.close() が呼ばれます。