web-dev-qa-db-fra.com

Rompre ou sortir de la déclaration "avec"?

Je voudrais juste sortir d'une déclaration with sous certaines conditions:

with open(path) as f:
    print 'before condition'
    if <condition>: break #syntax error!
    print 'after condition'

Bien sûr, ce qui précède ne fonctionne pas. Y a-t-il un moyen de faire cela? (Je sais que je peux inverser la condition: if not <condition>: print 'after condition' - de la même manière que ci-dessus?)

28
jmilloy

Le meilleur moyen serait de l'encapsuler dans une fonction et d'utiliser return:

def do_it():
    with open(path) as f:
        print 'before condition'
        if <condition>:
            return
        print 'after condition'
33
Trevor

with vous causer des ennuis? Jetez plus d'objets with- capables au problème!

class fragile(object):
    class Break(Exception):
      """Break out of the with statement"""

    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self.value.__enter__()

    def __exit__(self, etype, value, traceback):
        error = self.value.__exit__(etype, value, traceback)
        if etype == self.Break:
            return True
        return error

Enveloppez simplement l'expression que vous allez utiliser with avec fragile, et raise fragile.Break pour qu'elle éclate à tout moment!

with fragile(open(path)) as f:
    print 'before condition'
    if condition:
        raise fragile.Break
    print 'after condition'

Avantages de cette configuration

  • Utilise with et juste le with; ne place pas votre fonction dans une "boucle" sémantiquement trompeuse ou une fonction étroitement spécialisée, et ne vous oblige pas à gérer les erreurs en plus après le with.
  • Conserve vos variables locales à disposition au lieu de les transmettre à une fonction d'emballage.
  • Nestable!

    with fragile(open(path1)) as f:
        with fragile(open(path2)) as g:
            print f.read()
            print g.read()
            raise fragile.Break
            print "This wont happen"
        print "This will though!"
    

    De cette façon, vous n'avez pas besoin de créer une nouvelle fonction pour envelopper le with extérieur si vous voulez que les deux se cassent.

  • Ne nécessite pas de restructuration: emballez simplement ce que vous avez déjà avec fragile et vous voilà prêt à partir!

Inconvénients de cette configuration

  • N'utilise pas réellement une déclaration 'break'. Je ne peux pas tous les gagner;)
50
Orez

Je pense que vous devriez simplement restructurer la logique:

with open(path) as f:
    print 'before condition checked'
    if not <condition>:
        print 'after condition checked'
6
K. Brafford

Puisque break ne peut apparaître qu’à l’intérieur d’une boucle, vos options sont quelque peu limitées dans with à:

  • return (met "avec" + instructions associées dans la fonction)
  • sortie (caution du programme - probablement pas idéal)
  • exception (générer une exception à l'intérieur de "avec", capture ci-dessous)

Avoir une fonction et utiliser return est probablement la solution la plus propre et la plus simple ici si vous pouvez isoler la with et les instructions associées (et rien d’autre) à l’intérieur d’une fonction. 

Sinon, générez une exception dans la with si nécessaire, interceptez immédiatement en dessous/en dehors de la with pour continuer le reste du code.

Mise à jour : Comme OP le suggère dans les commentaires ci-dessous (peut-être tonuge à la joue?), On pourrait également envelopper la déclaration with dans une boucle pour faire fonctionner la break - bien que ce soit sournoisement trompeur. Donc, bien qu’il s’agisse d’une solution de travail, ce n’est probablement pas quelque chose qui serait recommandé).

5
Levon
f = open("somefile","r")
for line in f.readlines():
       if somecondition: break;
f.close()

Je ne pense pas que vous puissiez sortir de la ... vous devez utiliser une boucle ...

[edit] ou faites simplement la méthode de la fonction mentionnée par les autres

2
Joran Beasley

C’est une question ancienne, mais c’est une application de l’idiome pratique «à portée cassable». Intégrez simplement votre déclaration with à l'intérieur:

for _ in (True,):
    with open(path) as f:
        print 'before condition'
        if <condition>: break
        print 'after condition'

Cet idiome crée une "boucle", toujours exécutée exactement une fois, dans le seul but de renfermer un bloc de code dans une portée qui peut être rompue de manière conditionnelle. Dans le cas d'OP, il s'agissait d'une invocation de gestionnaire de contexte à inclure, mais il pouvait s'agir de toute séquence d'instructions délimitées pouvant nécessiter un échappement conditionnel.

La réponse acceptée est acceptable, mais cette technique fait la même chose sans qu'il soit nécessaire de créer une fonction, ce qui n'est pas toujours pratique ou souhaité.

2
user2137858

comme extrait abrégé:

class a:
    def __enter__(self):
        print 'enter'
    def __exit__(self ,type, value, traceback):
        print 'exit'

for i in [1]:
    with a():
        print("before")
        break
        print("after")

...

enter
before
exit
1
ARtnaMed

Vous pouvez tout mettre dans une fonction et lorsque la condition est vraie, appelez un retour.

1
YuriAlbuquerque

Il existe une fonction __exit__() à cet effet. La syntaxe est la suivante:

with VAR = EXPR:
  try:
    BLOCK
  finally:
    VAR.__exit__()
1
Nimbal Rahul