Как я могу открыть несколько файлов, используя «с открытым» в Python? - PullRequest
569 голосов
/ 06 января 2011

Я хочу изменить пару файлов одновременно, если Я могу записать все из них.Мне интересно, смогу ли я как-то объединить несколько открытых вызовов с помощью оператора 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

Если это невозможно, как бы выглядело элегантное решение этой проблемы?

Ответы [ 7 ]

880 голосов
/ 06 января 2011

Начиная с 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"

В большинстве случаев у вас есть переменный набор файлов, вы, вероятно, захотите открыть их один последругой, хотя.

91 голосов
/ 06 января 2011

Просто замените 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
44 голосов
/ 16 сентября 2016

Для одновременного открытия большого количества файлов или для длинных путей к файлам может быть полезно разбить элементы на несколько строк.Из Python Style Guide , предложенного @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())
7 голосов
/ 09 декабря 2017

Вложенные с заявлениями сделают ту же работу, и, на мой взгляд, с ними проще работать.

Допустим, у вас есть файл inFile.txt, и вы хотите записать его в два файла 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)

EDIT:

Я не понимаю причину понижения. Я проверил свой код перед публикацией своего ответа, и он работает, как нужно: пишет во все outFile, как и спрашивает вопрос. Нет дублирования записи или не писать. Поэтому мне действительно любопытно узнать, почему мой ответ считается неправильным, неоптимальным или чем-то подобным.

6 голосов
/ 18 ноября 2018

Начиная с 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]
2 голосов
/ 02 февраля 2018

С python 2.6 Это не будет работать, мы должны использовать следующий способ, чтобы открыть несколько файлов:

with open('a', 'w') as a:
    with open('b', 'w') as b:
1 голос
/ 06 апреля 2019

Поздний ответ (8 лет), но для тех, кто хочет объединить несколько файлов в один , может помочь следующая функция:

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
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...