Pythonで「with open」を使用して複数のファイルを開くにはどうすればよいですか?


670

私は、一度にファイルのカップルを変更したい場合に限っ私はそれらのすべてに書き込むことができます。どういうわけか、複数のオープンコールをwithステートメントと組み合わせることができるかどうか疑問に思っています。

try:
  with open('a', 'w') as a and open('b', 'w') as b:
    do_something()
except IOError as e:
  print 'Operation failed: %s' % e.strerror

それが不可能な場合、この問題のエレガントな解決策はどのようになりますか?

回答:


1050

Python 2.7(または3.1)では、次のように書くことができます

with open('a', 'w') as a, open('b', 'w') as b:
    do_something()

以前のバージョンのPythonでは、contextlib.nested()コンテキストマネージャをネストするために使用できる場合があります 。ただし、これは複数ファイルを開く場合には期待どおりに機能しません-詳細については、リンクされたドキュメントを参照してください。


さまざまな数のファイルを同時に開きたいというまれなケースではcontextlib.ExitStack、Pythonバージョン3.3以降、を使用できます。

with ExitStack() as stack:
    files = [stack.enter_context(open(fname)) for fname in filenames]
    # Do something with "files"

ほとんどの場合、ファイルの変数セットがあるので、ファイルを次々に開きたいと思うでしょう。


5
残念ながら、contextlib.nestedのドキュメントによると、ファイルを開くためにそれを使用するべきではありません。「nested()を使用して2つのファイルを開くことはプログラミングエラーです。 2番目のファイル。」
ウェロニカ2011

41
withファイルの可変リストを開く方法はありますか?
monkut 2013

23
@monkut:非常に良い質問です(実際に別の質問としてこれを尋ねることもできます)。短い答え:はい、ExitStackPython 3.3以降にあります。以前のバージョンのPythonでこれを行う簡単な方法はありません。
Sven Marnach 2013

12
この構文を複数行にまたがることは可能ですか?
tommy.carstensen 2014

9
@ tommy.carstensen:通常の行継続メカニズムを使用できます。PEP 9で推奨されているように、コンマで区切るにはバックスラッシュ行の継続を使用する必要があります。
Sven Marnach、2014年

99

ただ、交換するand,すれば完了です。

try:
    with open('a', 'w') as a, open('b', 'w') as b:
        do_something()
except IOError as e:
    print 'Operation failed: %s' % e.strerror

3
この構文をサポートするPythonのバージョンを指定する必要があります。
Craig McQueen

58

一度に多くのファイルを開く場合や長いファイルパスの場合は、複数の行に分割すると便利です。コメントで@Sven Marnachが提案したPythonスタイルガイドから別の回答へ:

with open('/path/to/InFile.ext', 'r') as file_1, \
     open('/path/to/OutFile.ext', 'w') as file_2:
    file_2.write(file_1.read())

1
このインデントで、「フレーク8:視覚的なインデントのために継続インデントされた継続行」
Louis M

@LouisMベースのpythonではなく、エディターや環境からのもののように聞こえます。それでも問題が解決しない場合は、それに関連する新しい質問を作成し、編集者と環境について詳しく説明することをお勧めします。
Michael Ohlrogge

3
はい、それは間違いなく私の編集者であり、警告にすぎません。私が強調したかったのは、あなたのインデントがPEP8に準拠していないということです。2番目のopen()を最初のopen()と揃えるのではなく、8つのスペースでインデントする必要があります。
Louis M

2
@LouisM PEP8はガイドラインであり、ルールではありません。この場合、私は間違いなく無視します
Nick

2
はい、それで問題ありませんが、自動リンターを使用している他の人にとっては役立つかもしれません:)
Louis M

14

入れ子のステートメントは同じ仕事をし、私の意見では、より簡単に対処できます。

inFile.txtがあり、2つのoutFileに同時に書き込みたいとします。

with open("inFile.txt", 'r') as fr:
    with open("outFile1.txt", 'w') as fw1:
        with open("outFile2.txt", 'w') as fw2:
            for line in fr.readlines():
                fw1.writelines(line)
                fw2.writelines(line)

編集:

反対票の理由がわかりません。回答を公開する前にコードをテストしましたが、問題なく機能します。質問のように、outFileのすべてに書き込みます。重複した書き込みや書き込みの失敗はありません。だから私は本当に私の答えが間違っている、最適ではない、またはそのようなものであると考えられている理由を知りたいと思っています。


1
他の誰かがあなたに投票した理由はわかりませんが、これはたまたま私が必要とするものである3つのファイル(1つの入力、2つの出力)を持つ唯一の例であるため、私はあなたを支持しました。
アダムマイケルウッド

2
多分あなたはPython> 2.6でbcozに反対票を投じているかもしれません-より多くのpythonicコードを書くことができます -gist.github.com/IaroslavR/3d8692e2a11e1ef902d2d8277eb88cb8(なぜ私はコメントにコードフラグメントを挿入できないのですか?過去
エルRuso

2
それらのうんざりするpython 2.6へのフレンドリーな注意:CentOS 6(2020年11月までEOLにはなりません)は、デフォルトでpy2.6を使用しています。したがって、この回答は(現時点では)全体として1つのIMOでも依然として最良です。
BJブラック

11

Python 3.3以降ExitStackcontextlibモジュールのクラスを使用して
、任意の数のファイルを安全に開くことができます

動的な数のコンテキスト対応オブジェクトを管理できます。つまり、処理するファイルの数がわからない場合に特に役立ちます

実際、ドキュメントに記載されている正規のユースケースでは、動的な数のファイルを管理しています。

with ExitStack() as stack:
    files = [stack.enter_context(open(fname)) for fname in filenames]
    # All opened files will automatically be closed at the end of
    # the with statement, even if attempts to open files later
    # in the list raise an exception

詳細に興味がある場合は、ExitStack動作方法を説明するための一般的な例を以下に示します。

from contextlib import ExitStack

class X:
    num = 1

    def __init__(self):
        self.num = X.num
        X.num += 1

    def __repr__(self):
        cls = type(self)
        return '{cls.__name__}{self.num}'.format(cls=cls, self=self)

    def __enter__(self):
        print('enter {!r}'.format(self))
        return self.num

    def __exit__(self, exc_type, exc_value, traceback):
        print('exit {!r}'.format(self))
        return True

xs = [X() for _ in range(3)]

with ExitStack() as stack:
    print(len(stack._exit_callbacks)) # number of callbacks called on exit
    nums = [stack.enter_context(x) for x in xs]
    print(len(stack._exit_callbacks))

print(len(stack._exit_callbacks))
print(nums)

出力:

0
enter X1
enter X2
enter X3
3
exit X3
exit X2
exit X1
0
[1, 2, 3]

3

python 2.6では動作しません。複数のファイルを開くには、以下の方法を使用する必要があります。

with open('a', 'w') as a:
    with open('b', 'w') as b:

1

遅い答え(8歳)ですが、複数のファイルを1つ結合したい場合は、次の関数が役立ちます。

def multi_open(_list):
    out=""
    for x in _list:
        try:
            with open(x) as f:
                out+=f.read()
        except:
            pass
            # print(f"Cannot open file {x}")
    return(out)

fl = ["C:/bdlog.txt", "C:/Jts/tws.vmoptions", "C:/not.exist"]
print(multi_open(fl))

2018-10-23 19:18:11.361 PROFILE  [Stop Drivers] [1ms]
2018-10-23 19:18:11.361 PROFILE  [Parental uninit] [0ms]
...
# This file contains VM parameters for Trader Workstation.
# Each parameter should be defined in a separate line and the
...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.