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
Où 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.
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:
.
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é
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.
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
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.
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()
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