Quelle est l'utilisation prévue de la clause facultative else
de l'instruction try
?
Les instructions du bloc else
sont exécutées si l'exécution tombe au bas de la try
- s'il n'y a pas eu d'exception. Honnêtement, je n'ai jamais trouvé un besoin.
Cependant, Gestion des exceptions remarque:
L’utilisation de la clause else est préférable à l’ajout de code supplémentaire à la clause try car elle évite d’attraper accidentellement une exception qui n’a pas été générée par le code protégé par l’instruction try ... except.
Donc, si vous avez une méthode qui pourrait, par exemple, lancer un IOError
et que vous voulez intercepter les exceptions qu’elle soulève, vous pouvez faire autre chose si la première opération aboutit, et vous ne veut pas attraper une erreur IOError à partir de cette opération, vous pourriez écrire quelque chose comme ceci:
try:
operation_that_can_throw_ioerror()
except IOError:
handle_the_exception_somehow()
else:
# we don't want to catch the IOError if it's raised
another_operation_that_can_throw_ioerror()
finally:
something_we_always_need_to_do()
Si vous ne mettez que another_operation_that_can_throw_ioerror()
après operation_that_can_throw_ioerror
, le except
interceptera les erreurs du second appel. Et si vous le mettez après tout le bloc try
, il sera toujours exécuté, et pas après le finally
. La else
vous permet de vous assurer que
finally
, etIOError
s qu'il soulève ne sont pas attrapés iciIl y a une grosse raison d'utiliser le style else
- et sa lisibilité. Il est généralement judicieux de conserver un code susceptible de provoquer des exceptions à proximité du code qui les traite. Par exemple, comparez ces:
try:
from EasyDialogs import AskPassword
# 20 other lines
getpass = AskPassword
except ImportError:
getpass = default_getpass
et
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
else:
# 20 other lines
getpass = AskPassword
La seconde est bonne lorsque la except
ne peut pas revenir plus tôt ou renvoyer l’exception. Si possible, j'aurais écrit:
try:
from EasyDialogs import AskPassword
except ImportError:
getpass = default_getpass
return False # or throw Exception('something more descriptive')
# 20 other lines
getpass = AskPassword
Remarque: Réponse copiée à partir du doublon récemment posté ici , d'où tout ce "AskPassword".
Une utilisation: tester du code qui devrait générer une exception.
try:
this_should_raise_TypeError()
except TypeError:
pass
except:
assert False, "Raised the wrong exception type"
else:
assert False, "Didn't raise any exception"
(Ce code devrait être résumé dans un test plus générique en pratique.)
Python try-else
Quelle est l'utilisation prévue de la clause optionnelle
else
de l'instruction try?
L'utilisation prévue est d'avoir un contexte pour que plus de code soit exécuté s'il n'y avait aucune exception où il devait être traité.
Ce contexte évite de manipuler accidentellement des erreurs inattendues.
Mais il est important de comprendre les conditions précises qui entraînent l'exécution de la clause else, car return
, continue
et break
peuvent interrompre le flux de contrôle en else
.
L'instruction else
est exécutée s'il existe aucune exception et si elle n'est pas interrompue par une instruction return
, continue
ou break
.
La clause facultative
else
est exécutée si et quand le contrôle se termine à la fin de la clausetry
. *
(Bold ajouté.) Et la note de bas de page se lit comme suit:
* Actuellement, le contrôle “coule de la fin” sauf dans le cas d'une exception ou de l'exécution d'une instruction
return
,continue
oubreak
.
Il nécessite au moins une clause d'exception précédente ( voir la grammaire ). Donc, ce n'est vraiment pas "try-else", c'est "try-except-else (-finally)", avec le else
(et finally
) étant facultatif.
Le tutoriel Python explique l'utilisation prévue:
L'instruction try ... except a une clause else optionnelle, qui, lorsqu'elle est présente, doit suivre toutes les clauses except. C'est utile pour le code qui doit être exécuté si la clause try ne déclenche pas d'exception. Par exemple:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
L’utilisation de la clause else est préférable à l’ajout de code supplémentaire à la clause try car elle évite d’attraper accidentellement une exception qui n’a pas été générée par le code protégé par l’instruction try ... except.
else
en fonction du code suivant le bloc try
Si vous gérez une erreur, le bloc else
ne sera pas exécuté. Par exemple:
def handle_error():
try:
raise RuntimeError('oops!')
except RuntimeError as error:
print('handled a RuntimeError, no big deal.')
else:
print('if this prints, we had no error!') # won't print!
print('And now we have left the try block!') # will print!
Et maintenant,
>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!
Try-except-else est idéal pour combiner le modèle EAFP avec saisie de canard :
try:
cs = x.cleanupSet
except AttributeError:
pass
else:
for v in cs:
v.cleanup()
Vous pourriez penser que ce code naïf convient parfaitement:
try:
for v in x.cleanupSet:
v.clenaup()
except AttributeError:
pass
C'est un excellent moyen de cacher accidentellement des bugs graves dans votre code. J'ai typo-ed nettoyage là-bas, mais l'attributError qui me permet de savoir est en train d'être avalé. Pire encore, si je l'avais écrit correctement, mais que la méthode de nettoyage recevait parfois un type d'utilisateur doté d'un attribut mal nommé, ce qui entraînait un échec silencieux à mi-parcours et laissait un fichier non fermé? Bonne chance pour déboguer celui-là.
Je trouve cela très utile lorsque vous avez un nettoyage à faire, cela doit être fait même s'il y a une exception:
try:
data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
handle_exception(e)
else:
do_stuff(data)
finally:
clean_up()
Même si vous ne pouvez pas penser à une utilisation pour le moment, vous pouvez parier que cela doit être utile. Voici un exemple sans imagination:
Avec else
:
a = [1,2,3]
try:
something = a[2]
except:
print "out of bounds"
else:
print something
Sans else
:
try:
something = a[2]
except:
print "out of bounds"
if "something" in locals():
print something
Ici, vous avez la variable something
définie si aucune erreur n'est renvoyée. Vous pouvez le supprimer en dehors du bloc try
, mais cela nécessite une détection compliquée si une variable est définie.
De Erreurs et exceptions # Gestion des exceptions - docs.python.org
L'instruction
try ... except
comporte une clause facultativeelse
, qui, lorsqu'elle est présente, doit respecter toutes les clauses sauf. C'est utile pour le code qui doit être exécuté si la clause try ne déclenche pas d'exception. Par exemple:for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
L’utilisation de la clause else est préférable à l’ajout de code supplémentaire à la clause try car elle évite d’attraper accidentellement une exception qui n’a pas été générée par le code protégé par l’instruction try ... except.
Il y a un bel exemple de try-else
dans PEP 38 . Fondamentalement, il s’agit de gérer différentes exceptions dans différentes parties de l’algorithme.
C'est quelque chose comme ça:
try:
do_init_stuff()
except:
handle_init_suff_execption()
else:
try:
do_middle_stuff()
except:
handle_middle_stuff_exception()
Cela vous permet d'écrire le code de gestion des exceptions plus près de l'endroit où l'exception se produit.
En regardant référence Python , il semble que else
soit exécuté après try
quand il n'y a pas d'exception. La clause optionnelle else est exécutée si et quand le contrôle sort de la fin de la clause try. 2 Les exceptions dans la clause else ne sont pas gérées par les clauses d'exception précédentes.
Plongez dans python a un exemple où, si je comprends bien, dans le bloc try
, ils essaient d'importer un module. Lorsque cela échoue, vous obtenez une exception et une liaison par défaut, mais lorsque cela fonctionne, vous avez option d'aller dans else
bloquer et lier ce qui est requis (voir le lien pour l'exemple et l'explication).
Si vous essayez de travailler dans le bloc catch
, il risque de lever une autre exception - je suppose que c'est là que le bloc else
est utile.
C'est ça. Le bloc 'else' d'une clause try-except existe pour le code qui s'exécute quand (et seulement quand) l'opération essayée aboutit. Il peut être utilisé et abusé.
try:
fp= open("configuration_file", "rb")
except EnvironmentError:
confdata= '' # it's ok if the file can't be opened
else:
confdata= fp.read()
fp.close()
# your code continues here
# working with (possibly empty) confdata
Personnellement, je l’aime bien et je l’utilise quand cela convient. Il groupe sémantiquement les déclarations.
La plupart des réponses semblent se concentrer sur les raisons pour lesquelles nous ne pouvons pas simplement mettre le matériau dans la clause else de la clause try elle-même. La question la clause else dans l'instruction try ... à quoi sert-elle correctement demande spécifiquement pourquoi le code de la clause else ne peut pas aller après le bloc d'essai lui-même, et cette question est dupée à celle-ci, mais je ne vois pas de réponse claire à cette question ici. Je me sens https://stackoverflow.com/a/3996378/150312 répond parfaitement à cette question. J'ai également essayé d'élucider la signification des différentes clauses de https://stackoverflow.com/a/22579805/150312 .
Peut-être une utilisation pourrait être:
#debug = []
def debuglog(text, obj=None):
" Simple little logger. "
try:
debug # does global exist?
except NameError:
pass # if not, don't even bother displaying
except:
print('Unknown cause. Debug debuglog().')
else:
# debug does exist.
# Now test if you want to log this debug message
# from caller "obj"
try:
if obj in debug:
print(text) # stdout
except TypeError:
print('The global "debug" flag should be an iterable.')
except:
print('Unknown cause. Debug debuglog().')
def myfunc():
debuglog('Made it to myfunc()', myfunc)
debug = [myfunc,]
myfunc()
Peut-être que cela vous mènera aussi à une utilisation.
J'ai trouvé la construction try: ... else:
utile dans le cas où vous exécutez des requêtes de base de données et que vous enregistrez les résultats de ces requêtes dans une base de données distincte du même type/saveur. Disons que j'ai beaucoup de threads de travail qui traitent toutes les requêtes de base de données soumises à une file d'attente
#in a long running loop
try:
query = queue.get()
conn = connect_to_db(<main db>)
curs = conn.cursor()
try:
curs.execute("<some query on user input that may fail even if sanitized">)
except DBError:
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of failed query")
logcurs.close()
logconn.close()
else:
#we can't put this in main try block because an error connecting
#to the logging DB would be indistinguishable from an error in
#the mainquery
#We can't put this after the whole try: except: finally: block
#because then we don't know if the query was successful or not
logconn = connect_to_db(<logging db>)
logcurs = logconn.cursor()
logcurs.execute("<update in DB log with record of successful query")
logcurs.close()
logconn.close()
#do something in response to successful query
except DBError:
#This DBError is because of a problem with the logging database, but
#we can't let that crash the whole thread over what might be a
#temporary network glitch
finally:
curs.close()
conn.close()
#other cleanup if necessary like telling the queue the task is finished
Bien sûr, si vous pouvez faire la distinction entre les exceptions possibles pouvant être émises, vous n’aurez pas à les utiliser, mais si le code réagit à un élément de code réussi, il risque de générer la même exception que l’expérience réussie, et vous ne pouvez pas simplement laissez la deuxième exception possible disparaître ou revenez immédiatement en cas de succès (ce qui tuerait le fil de discussion dans mon cas), alors cela vous sera utile.
J'ai trouvé else
utile pour traiter un fichier de configuration éventuellement incorrect:
try:
value, unit = cfg['lock'].split()
except ValueError:
msg = 'lock monitoring config must consist of two words separated by white space'
self.log('warn', msg)
else:
# get on with lock monitoring if config is ok
Une exception à la lecture de lock
config désactive la surveillance de verrouillage et ValueErrors enregistre un message d'avertissement utile.
L'un des scénarios d'utilisation auquel je peux penser est constitué par des exceptions imprévisibles, qui peuvent être contournées si vous essayez à nouveau. Par exemple, lorsque les opérations du bloc try impliquent des nombres aléatoires:
while True:
try:
r = random.random()
some_operation_that_fails_for_specific_r(r)
except Exception:
continue
else:
break
Mais si l’exception peut être prédite, vous devez toujours choisir la validation au préalable par rapport à une exception. Cependant, tout ne peut pas être prédit, ce modèle de code a donc sa place.
Voici un autre endroit où j'aime utiliser ce motif:
while data in items:
try
data = json.loads(data)
except ValueError as e:
log error
else:
# work on the `data`
Un bloc else
peut souvent exister pour compléter les fonctionnalités présentes dans chaque bloc except
.
try:
test_consistency(valuable_data)
except Except1:
inconsistency_type = 1
except Except2:
inconsistency_type = 2
except:
# Something else is wrong
raise
else:
inconsistency_type = 0
"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""
Dans ce cas, inconsistency_type
est défini dans chaque bloc sauf, de sorte que le comportement est complété dans le cas d'absence d'erreur dans else
.
Bien sûr, je décris cela comme un motif qui peut apparaître dans votre propre code un jour. Dans ce cas particulier, vous devez tout simplement définir inconsistency_type
sur 0 avant le bloc try
.
Supposons que votre logique de programmation dépend de la présence d'un dictionnaire avec une clé donnée. Vous pouvez tester le résultat de dict.get(key)
à l'aide de la construction if... else...
, ou vous pouvez:
try:
val = dic[key]
except KeyError:
do_some_stuff()
else:
do_some_stuff_with_val(val)