web-dev-qa-db-fra.com

Python multiligne avec instruction

Quelle est une façon propre de créer un with multi-lignes en python? Je veux ouvrir plusieurs fichiers dans un seul with, mais c'est assez loin à droite que je le veux sur plusieurs lignes. Comme ça:

class Dummy:
    def __enter__(self): pass
    def __exit__(self, type, value, traceback): pass

with Dummy() as a, Dummy() as b,
     Dummy() as c:
    pass

Malheureusement, c'est un SyntaxError. J'ai donc essayé ceci:

with (Dummy() as a, Dummy() as b,
      Dummy() as c):
    pass

Également une erreur de syntaxe. Cependant, cela a fonctionné:

with Dummy() as a, Dummy() as b,\
     Dummy() as c:
    pass

Et si je voulais placer un commentaire? Cela ne fonctionne pas:

with Dummy() as a, Dummy() as b,\
     # my comment explaining why I wanted Dummy() as c\
     Dummy() as c:
    pass

Il n'y a pas non plus de variation évidente sur l'emplacement du \s.

Existe-t-il un moyen propre de créer une instruction with sur plusieurs lignes qui autorise les commentaires à l'intérieur?

40
Justin

Étant donné que vous avez balisé ceci Python 3, si vous devez intercaler des commentaires avec vos gestionnaires de contexte, j'utiliserais un contextlib.ExitStack :

with ExitStack() as stack:
    a = stack.enter_context(Dummy()) # Relevant comment
    b = stack.enter_context(Dummy()) # Comment about b
    c = stack.enter_context(Dummy()) # Further information

Cela équivaut à

with Dummy() as a, Dummy() as b, Dummy() as c:

Cela a l'avantage que vous pouvez générer vos gestionnaires de contexte dans une boucle au lieu de devoir répertorier chacun séparément. La documentation donne l'exemple que si vous voulez ouvrir un tas de fichiers et que vous avez les noms de fichiers dans une liste, vous pouvez le faire

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

Si vos gestionnaires de contexte prennent tellement d'espace à l'écran que vous souhaitez mettre des commentaires entre eux, vous en avez probablement assez pour vouloir utiliser une sorte de boucle.


Comme le mentionne M. Deathless dans les commentaires, il y a un contextlib backport sur PyPI sous le nom contextlib2. Si vous êtes sur Python 2, vous pouvez utiliser l'implémentation du backport de ExitStack.

44
user2357112

Cela me semble le plus simple:

with open('firstfile', 'r') as (f1 # first
  ), open('secondfile', 'r') as (f2 # second
  ):
    pass
13
TigerhawkT3

Ce n'est pas exactement propre, mais vous pouvez le faire:

with Dummy() as a, Dummy() as b, (
     #my comment
     Dummy()) as c:
    pass

Il n'y a pas d'erreurs de syntaxe, mais ce n'est pas le plus propre. Vous pouvez également faire ceci:

with Dummy() as a, Dummy() as b, Dummy(
     #my comment
     ) as c:
    pass

Pensez à trouver un moyen de le faire sans utiliser les commentaires au milieu du with.

2
Justin

Je garderais les choses simples et lisibles en ajoutant le commentaire avant l'instruction with, ou sur la ligne elle-même:

# my comment explaining why I wanted Dummy() as c
with Dummy() as a, Dummy() as b,\
     Dummy() as c: # or add the comment here
    pass
1
MiniQuark

Comme réponse de TigerhawkT , mais avec un retrait qui ne déclenche pas erreur E124 de pycodestyle :

with (
        open('firstfile', 'r')) as f1, (  # first
        open('secondfile', 'r')) as f2:  # second
    pass

OMI c'est toujours moche, mais au moins ça passe le linter.

0
wjandrea