26.5 contextlib -- with-構文 コンテキストのためのユーティリティ。

バージョン 2.5 で 新たに追加 された仕様です。

このモジュールはwith文を必要とする一般的なタスクのための ユーティリティを提供します。

用意されている関数:

contextmanager( func)
この関数はデコレータであり、with文コンテキストマネージャのための ファクトリ関数の定義に利用できます。 ファクトリ関数を定義するために、クラスあるいは 別の__enter__()__exit__()メソッドを作る必要はありません。

簡単な例(実際にHTMLを生成する方法としてはお勧めできません!):

from __future__ import with_statement
from contextlib import contextmanager

@contextmanager
def tag(name):
    print "<%s>" % name
    yield
    print "</%s>" % name

>>> with tag("h1"):
...    print "foo"
...
<h1>
foo
</h1>

デコレートされた関数は呼び出されたときにジェネレータ-イテレータを返します。 このイテレータは値をちょうど一つyieldしなければなりません。 with文のas節が存在するなら、 その値がas節のターゲットへ束縛されることになります。

ジェネレータがyieldするところで、with文のネストされたブロックが実行されます。 ジェネレータはブロックから出た後に再開されます。ブロック内で処理されない例外が発生した場合は、 yieldが起きた場所でジェネレータ内部へ再送出されます。 このように、(もしあれば)エラーを捕捉したり、後片付け処理を確実に実行したりするために、 try...except...finally文を使うことができます。 単に例外のログをとるためだけに、もしくは(完全に例外を抑えてしまうのではなく) あるアクションを実行するだけに例外を捕まえるなら、ジェネレータはその例外を再送出しなければなりません。 そうしないと、ジェネレータコンテキストマネージャは例外が処理されたwith文を指しており、 そのwith文のすぐ後につづく文から実行を再開します。

nested( mgr1[, mgr2[, ...]])
複数のコンテキストマネージャを一つのネストされたコンテキストマネージャへ結合します。

このようなコードは:

from contextlib import nested

with nested(A, B, C) as (X, Y, Z):
    do_something()

これと同等です:

with A as X:
    with B as Y:
        with C as Z:
            do_something()

ネストされたコンテキストマネージャの一つの__exit__()メソッドに 止めるべき例外がある場合は、残りの外側のコンテキストマネージャすべてに 例外情報が渡されないということに注意してください。 同じように、ネストされたマネージャの一つの__exit__()メソッドが 例外を送出したならば、どんな以前の例外状態も失われ、 新しい例外が残りすべての外側にあるコンテキストマネージャの __exit__()メソッドに渡されます。 一般的に__exit__()メソッドが例外を送出することは避けるべきであり、 特に渡された例外を再送出すべきではありません。

closing( thing)
ブロックの完了時にthingを閉じるコンテキストマネージャを返します。 これは基本的に以下と等価です:

from contextlib import contextmanager

@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()

そして、明確にpageを閉じる必要なしに、このように書くことができます:

from __future__ import with_statement
from contextlib import closing
import codecs

with closing(urllib.urlopen('http://www.python.org')) as page:
    for line in page:
        print line

たとえエラーが発生したとしても、withブロックを出るときに page.close()が呼ばれます。

参考:

PEP 0343, The "with" statement
仕様、背景、および、Python with文の例。
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。