3.3以降でExitStack
は、間違いなく答えです。実際、これはドキュメントに記載されている最初の例です。
with ExitStack() as stack:
files = [stack.enter_context(open(path) for path in path_list]
for f in files:
do_something(f)
もちろん、あなたのwith
body が本当にただのループでfiles
あるなら、これを行う理由はありません —with
ループ内に各ファイルのステートメントを入れるだけです。(実際、これを行わないのには十分な理由があります。一度に 1 つずつ使用するためだけに、おそらく無制限の数のファイル ハンドルを一度に開く必要があるでしょうか?) しかし、おそらく実際のコードでは、同時に複数のファイルを使用する必要があります。
以前のバージョンでは、 3.3 ソースExitStack
から簡単に借りることができました。3.2 へのバックポートは簡単です。2.7 の場合、適切な例外コンテキストを保証するために、例外伝播で凝ったものを取り除く (または必要に応じて書き直す) 必要がありますが、それは非常に簡単です。
ただし、さらに優れた解決策は、おそらくcontextlib2
PyPI からインストールすることです。これは、「標準ライブラリの contextlib モジュールの最新バージョンの機能を以前の Python バージョンにバックポートする」ものです。contextlib2.ExitStack
次に、の代わりに使用できますcontextlib.ExitStack
。(実際にcontextlib2
は、 Python 3.3 よりも前にExitStack
、暫定的な名前でを持っていました…)ContextStack
closing_all
ただし、stdlib に似ていますclosing
が、複数の目的でコンテキスト マネージャーを簡単に構築することもできます。
@contextlib.contextmanager
def closing_all(things):
try:
yield things
finally:
for thing in things:
thing.close()
メソッドが発生させる可能性のあるものを処理する必要がある場合close
は、もう少し賢くする必要がありますが、ファイル オブジェクトや、 で使用する他のほとんどの型ではclosing
、その必要はありません。
より大きな問題は、例外が発生する可能性がある場合、実際に引数open
として渡すことができる有効なシーケンスを見つけるのが難しいことです。things
しかし、それが問題ではない場合、それを使用することは以下よりもさらに簡単ですExitStack
:
with closing_all(open(path) for path in path_list) as files:
for f in fs:
do_something(f)
s を実行して でラップする を構築することもできますがopening_all(paths, mode='r')
、それはあまり追加されないと思います。open
closing_all
もちろん、これを頻繁に行う必要がある場合、最良の答えは、opening_all
周りに構築しExitStack
、気にしないことclosing_all
です。