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)
もちろん、あなたのwithbody が本当にただのループでfilesあるなら、これを行う理由はありません —withループ内に各ファイルのステートメントを入れるだけです。(実際、これを行わないのには十分な理由があります。一度に 1 つずつ使用するためだけに、おそらく無制限の数のファイル ハンドルを一度に開く必要があるでしょうか?) しかし、おそらく実際のコードでは、同時に複数のファイルを使用する必要があります。
以前のバージョンでは、 3.3 ソースExitStackから簡単に借りることができました。3.2 へのバックポートは簡単です。2.7 の場合、適切な例外コンテキストを保証するために、例外伝播で凝ったものを取り除く (または必要に応じて書き直す) 必要がありますが、それは非常に簡単です。
ただし、さらに優れた解決策は、おそらくcontextlib2PyPI からインストールすることです。これは、「標準ライブラリの 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')、それはあまり追加されないと思います。openclosing_all
もちろん、これを頻繁に行う必要がある場合、最良の答えは、opening_all周りに構築しExitStack、気にしないことclosing_allです。