前のトピックへ

27.5. warnings — 警告の制御

次のトピックへ

27.7. abc — 抽象基底クラス

このページ

27.6. contextlibwith -構文コンテキストのためのユーティリティ

バージョン 2.5 で追加.

このモジュールは with 構文に関わる一般的なタスクのためのユーティリティを提供します。詳しい情報は、 コンテキストマネージャ型with文とコンテキストマネージャ を参照してください。

提供されている関数:

contextlib.contextmanager(func)

この関数は 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 文の直後の文から実行を再開します。

contextlib.nested(mgr1[, mgr2[, ...]])

複数のコンテキストマネージャを一つのネストされたコンテキストマネージャへ結合します。

このようなコードは

from contextlib import nested

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

これと同等です:

m1, m2, m3 = A(), B(), C()
with m1 as X:
    with m2 as Y:
        with m3 as Z:
            do_something()

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

contextlib.closing(thing)

ブロックの完了時に 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() が呼ばれます。

参考

PEP 0343 - The “with” statement

仕様、背景、および、Python with 文の例。