854 votes

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

Je veux modifier quelques fichiers en une seule fois, si Je peux leur écrire à tous. Je me demande si je ne peux pas combiner les appels ouverts multiples avec le système de gestion de l'information. with déclaration :

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'est pas possible, à quoi ressemblerait une solution élégante à ce problème ?

2 votes

Une autre question similaire : Plusieurs variables dans une instruction "with" ?

1312voto

Sven Marnach Points 133943

À 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 la commande contextlib.nested() pour imbriquer les gestionnaires de contexte. Cela ne fonctionnera pas comme prévu pour l'ouverture de plusieurs fichiers, cependant -- voir la documentation liée pour plus de détails.


Dans le cas rare où vous voulez ouvrir un nombre variable de fichiers en même temps, vous pouvez utiliser contextlib.ExitStack à partir de la version 3.3 de Python :

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

La plupart du temps, vous disposez d'un ensemble variable de fichiers, mais vous souhaitez probablement les ouvrir l'un après l'autre.

0 votes

Oui si cool que quelques lignes de code permettent de faire cela dans les versions précédentes de python également, comme dans cet exemple ici : metapython.blogspot.com/2010/12/

6 votes

Malheureusement, selon la docs contextlib.nested, vous ne devriez pas l'utiliser pour l'ouverture de fichiers : "utiliser nested() pour ouvrir deux fichiers est une erreur de programmation car le premier fichier ne sera pas fermé rapidement si une exception est levée lors de l'ouverture du second fichier."

52 votes

Existe-t-il un moyen d'utiliser with pour ouvrir une liste variable de fichiers ?

124voto

Michael Points 4361

Il suffit de remplacer and avec , 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

7 votes

Vous devez préciser quelles versions de Python prennent en charge cette syntaxe.

86voto

Michael Ohlrogge Points 6401

Pour ouvrir plusieurs fichiers à la fois ou pour les longs chemins d'accès aux fichiers, il peut être utile de répartir les choses sur plusieurs lignes. De la Guide de style Python comme 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())

1 votes

Avec cette indentation, j'obtiens : "flake8 : continuation de la ligne surindentée pour l'indentation visuelle"

0 votes

@LouisM Cela semble provenir de votre éditeur ou de votre environnement, plutôt que de la base python. Si cela continue à être un problème pour vous, je vous recommande de créer une nouvelle question à ce sujet et de donner plus de détails sur votre éditeur et votre environnement.

4 votes

Oui, c'est bien mon éditeur, et ce n'est qu'un avertissement. Ce que je voulais souligner, c'est que votre indentation n'est pas conforme à PEP8. Vous devriez indenter le deuxième open() de 8 espaces au lieu de l'aligner avec le premier.

30voto

Chris_Rands Points 15161

À partir de Python 3.10, il y a une nouvelle fonctionnalité de Les gestionnaires de contexte entre parenthèses qui permet une syntaxe telle que :

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

2 votes

Intéressant. Ça ajoute une paire de parenthèses supplémentaires. Peut-il faire quelque chose que with open("a", "w") as a, open ("b", "w") as b: ne pouvait pas faire ?

5 votes

@PatrickT Il permet de répartir la syntaxe sur plusieurs lignes sans saut de ligne, ce qui peut être plus lisible pour les longs exemples.

0 votes

Je l'ai eu ! Merci Chris !

27voto

timgeb Points 5966

Depuis Python 3.3, vous pouvez utiliser la classe ExitStack de la contextlib module pour sécuriser
ouvrir un nombre arbitraire de fichiers .

Il peut gérer un dynamique nombre d'objets contextuels, ce qui signifie qu'il s'avérera particulièrement utile si vous ne savez pas combien de fichiers vous allez traiter .

En fait, le cas d'utilisation canonique qui est 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 vous expliquer le fonctionnement du système. ExitStack fonctionne :

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]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X