web-dev-qa-db-ja.com

Pythonで "with open"を使って複数のファイルを開くにはどうすればいいですか?

一度にいくつかのファイルを変更したい、 iff 私はそれらのすべてに書き込むことができます。私はどういうわけか私がwithステートメントで複数のopen呼び出しを組み合わせることができるかどうか疑問に思います:

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

それが不可能な場合、この問題に対する優雅な解決策はどのようなものですか?

553
Frantischeck003

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

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

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


まれに、可変数のファイルをすべて同時に開きたい場合は、Pythonバージョン3.3以降、 contextlib.ExitStack を使用できます。

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

たいていの場合、ファイルの可変セットを持っているので、それらを次々に開きたいと思うかもしれません。

849
Sven Marnach

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
91
Michael

一度に多くのファイルを開く場合や長いファイルパスを扱う場合は、複数行に分割すると便利な場合があります。 Pythonスタイルガイド から@Sven Marnachが他の回答へのコメントで示唆しているように:

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())
43

ステートメントを入れ子にしても同じことができますが、私の意見では、もっと簡単に対処できます。

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のすべてに書き込みます。重複した書き込みや書き込みの失敗はありません。それで、私の答えが間違っている、最善ではない、またはそのようなものであると考えられる理由を知りたいのですが、私は本当に興味があります。

8
FatihAkici

Python 3.3以降、 ExitStack モジュールからクラス contextlib を安全に使用することができます。
任意の数のファイルを開く

それは 動的 コンテキストアウェアなオブジェクトの数を管理することができます、それはそれが特に有用であることを証明することを意味します あなたがあなたが扱うファイルの数を知らないなら .

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

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]
4
timgeb

Python 2.6ではうまくいきません。複数のファイルを開くには以下の方法を使用しなければなりません。

with open('a', 'w') as a:
    with open('b', 'w') as b:
3
Aashutosh jha

回答が遅い(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
...
1
Pedro Lobito