web-dev-qa-db-fra.com

'Enfin' équivalent pour les instructions If/Elif en Python

Python a-t-il un équivalent finally pour ses instructions if/else, similaire à ses instructions try/except/finally? Quelque chose qui nous permettrait de simplifier ceci:

 if condition1:
      do stuff
      clean up
 Elif condition2:
      do stuff
      clean up
 Elif condition3:
      do stuff
      clean up
 ...
 ...

pour ça:

 if condition1:
      do stuff
 Elif condition2:
      do stuff
 Elif condition3:
      do stuff
 ...
 ...
 finally:
      clean up

finally ne serait appelé qu'une fois la condition remplie et son exécution exécutée? Inversement, si aucune condition n'est remplie, le code finally ne sera pas exécuté. 

Je n'aime pas vomir de blasphème, mais la meilleure façon de le décrire est qu'il existe une déclaration GOTO à la fin de chaque bloc de 'choses à faire' qui a conduit à finally.

Pour l’essentiel, cela fonctionne comme le contraire d’une déclaration else. Alors que else n'est exécuté que si aucune autre condition n'est remplie, ceci ne sera exécuté QUE SI une autre condition est remplie.

17
nobillygreen

Cela peut être fait de manière totalement non-bidouillement comme ceci:

def function(x,y,z):
    if condition1:
        blah
    Elif condition2:
        blah2
    else:
        return False

    #finally!
    clean up stuff.

À certains égards, pas aussi pratique, car vous devez utiliser une fonction distincte. Cependant, bonne pratique à ne pas faire trop longtemps fonctionne de toute façon. Séparer votre logique en petites fonctions faciles à lire (généralement d'une page maximum) facilite les tests, la documentation et la compréhension du flux d'exécution.

Une chose à savoir est que la clause finally ne sera pas exécutée en cas d’exception. Pour ce faire, vous devez également ajouter des éléments try:.

10
Daniel Fairhead

Votre logique s'apparente à ceci:

cleanup = True
if condition1:
    do stuff
Elif condition2:
    do stuff
Elif condition3:
    do stuff
....
else:
    cleanup = False

if cleanup:
    do the cleanup

Moche, mais c'est ce que vous avez demandé

3
Ricardo Cárdenes

Une autre suggestion, qui pourrait vous convenir si les conditions sont pré-calculées.

if condition1:
    do stuff
Elif condition2:
    do stuff
...
if any([condition1, condition2, ...]):
    clean_up

Ce serait un problème si vous évaluiez les conditions dans le cadre de vos déclarations if, car vous devrez alors les évaluer une seconde fois pour la fonction any ... à moins que Python ne soit plus intelligent que je ne le réalise.

1
Pig

La réponse de mhlester a un code répétitif, une version améliorée pourrait être la suivante:

class NoCleanUp(Exception):
    pass

try:
    if condition1:
        do stuff
    Elif condition2:
        do stuff
    else:
        raise NoCleanUp
except NoCleanUp:
    pass
else:
    cleanup
1
JLT

Comme ça:

def stuff1:
  pass

def stuff2:
  pass

actions={condition1:stuff1, condition2:stuff2}

action = actions.get(condition, None)
if action:
  action()
  cleanup()

Les mises en garde sont bien sûr que vos clés de condition doivent être uniques. Vous pouvez contourner ce problème en disposant une hiérarchie hiérarchisée d'actions dict. 

0
DylanYoung

Un peu tard pour le parti, mais voir la question a été active récemment.

D'habitude je ferais un gestionnaire de contexte comme celui-ci

class CleanUp(object):

    class Cancel(Exception):
        pass

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

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception_value, traceback):

        cancelled = exception_type and issubclass(exception_type, self.__class__.Cancel)

        if not cancelled:
            self.f_cleanup()

        return not exception_type or cancelled

    def cancel(self):
        raise self.__class__.Cancel

Et puis vous pouvez l'utiliser comme ça

def cleanup():
    print "Doing Housekeeping"


with CleanUp(cleanup) as manager:
    if condition1:
        do stuff
    Elif condition2:
        do stuff
    else:
        manager.cancel()
0
Claus Nielsen

Est-ce hideux?

for _ in range(1):
    if condition1:
        do stuff
        break
    Elif condition2:
        do stuff
        break
else:
    finally stuff

Que dis-tu de ça?

class NoFinally(Exception):
    pass

try:
    if condition1:
        do stuff
        raise NoFinally
    Elif condition2:
        do stuff
        raise NoFinally
except NoFinally:
    pass
else:
    finally

Honnêtement, je déteste ces deux

0
mhlester