27.7. contextlib — with -構文コンテキストのためのユーティリティ — Python 2.7ja1 documentation

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.7ja1 documentation »
- Python 標準ライブラリ »
- 27. Python ランタイムサービス »

# 27.7. `contextlib` — `with` -構文コンテキストのためのユーティリティ

バージョン 2.5 で追加.

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

参考

最新バージョンの contextlib Python source code

提供されている関数:

`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[, ...]])

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

  この関数は、 `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 文がこの関数の機能を(この関数と違って奇妙なエラーを発生させることなしに) 直接サポートしました。

`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` 文の例。

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.7ja1 documentation »
- Python 標準ライブラリ »
- 27. Python ランタイムサービス »