web-dev-qa-db-fra.com

Comment puis-je ouvrir plusieurs fichiers avec "with open" en Python?

Je veux changer quelques fichiers en même temps, szf Je peux écrire à tous. Je me demande si je peux d'une manière ou d'une autre combiner les multiples appels ouverts avec l'instruction 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

Si ce n'était pas possible, à quoi ressemblerait une solution élégante à ce problème?

587
Frantischeck003

À partir de Python 2.7 (ou 3.1 respectivement), vous pouvez écrire

_with open('a', 'w') as a, open('b', 'w') as b:
    do_something()
_

Dans les versions antérieures de Python, vous pouvez parfois utiliser contextlib.nested() pour imbriquer des gestionnaires de contexte. Toutefois, cela ne fonctionnera pas comme prévu pour l'ouverture de plusieurs fichiers - voir la documentation liée pour plus de détails.


Dans les rares cas où vous souhaitez ouvrir simultanément un nombre variable de fichiers, vous pouvez utiliser contextlib.ExitStack , à partir de Python version 3.3:

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

La plupart du temps, vous avez un ensemble variable de fichiers. Toutefois, vous souhaiterez probablement les ouvrir l'un après l'autre.

911
Sven Marnach

Il suffit de remplacer and par , et vous avez terminé:

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

Pour ouvrir plusieurs fichiers en même temps ou pour des chemins de fichiers longs, il peut être utile de séparer les éléments sur plusieurs lignes. Du Guide de style Python suggéré par @Sven Marnach dans les commentaires d'une autre réponse:

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())
44
Michael Ohlrogge

Les déclarations imbriquées feront le même travail et, à mon avis, sont plus simples à traiter.

Disons que vous avez inFile.txt et que vous voulez l'écrire dans deux fichiers OutFile simultanément.

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)

MODIFIER:

Je ne comprends pas la raison du vote négatif. J'ai testé mon code avant de publier ma réponse, et cela fonctionne comme souhaité: il écrit dans tous les fichiers de outFile, exactement comme le demande la question. Pas d'écriture en double ou de non-écriture. Je suis donc vraiment curieux de savoir pourquoi ma réponse est considérée comme fausse, non optimale ou quelque chose du genre.

7
FatihAkici

Depuis Python 3.3, vous pouvez utiliser la classe ExitStack du module contextlib pour vous protéger en toute sécurité.
ouvre un nombre arbitraire de fichiers .

Il peut gérer un nombre dynamique d'objets sensibles au contexte, ce qui signifie qu'il sera particulièrement utile si vous ne savez pas combien de fichiers vous avez. aller à gérer .

En fait, le cas d'utilisation canonique mentionné dans la documentation est la gestion d'un nombre dynamique de fichiers.

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

Si les détails vous intéressent, voici un exemple générique pour expliquer le fonctionnement de 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)

Sortie:

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

Avec python 2.6 Cela ne fonctionnera pas, nous devons utiliser le moyen ci-dessous pour ouvrir plusieurs fichiers:

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

Réponse tardive (8 ans), mais pour quelqu'un qui cherche à joindre plusieurs fichiers en un, la fonction suivante peut être utile:

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