150 votes

Vaut-il mieux "essayer" quelque chose et attraper l'exception ou tester d'abord si c'est possible d'éviter une exception ?

Dois-je tester if quelque chose est valable ou juste try pour le faire et attraper l'exception ?

  • Existe-t-il une documentation solide indiquant qu'une voie est préférable ?
  • Est-ce qu'un moyen est plus pythonique ?

Par exemple, devrais-je :

if len(my_list) >= 4:
    x = my_list[3]
else:
    x = 'NO_ABC'

Ou :

try:
    x = my_list[3]
except IndexError:
    x = 'NO_ABC'

Quelques réflexions...
PEP 20 dit :

Les erreurs ne doivent jamais passer en silence.
Sauf si elle est explicitement réduite au silence.

L'utilisation d'un try au lieu d'un if être interprété comme une erreur passant silencieusement ? Et si c'est le cas, est-ce que vous la réduisez explicitement au silence en l'utilisant de cette façon, ce qui la rend OK ?


Je suis no se référant à des situations où vous ne pouvez faire les choses que d'une seule façon ; par exemple :

try:
    import foo
except ImportError:
    import baz

172voto

Remi Points 4223

Vous devriez préférer try/except sur if/else si cela entraîne

  • des accélérations (par exemple en évitant des recherches supplémentaires)
  • un code plus propre (moins de lignes/plus facile à lire)

Souvent, ils vont de pair.


accélère

Dans le cas où l'on essaie de trouver un élément dans une longue liste par :

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'

l'essai, sauf est la meilleure option lorsque le index se trouve probablement dans la liste et l'IndexError n'est généralement pas soulevé. De cette façon, vous évitez la nécessité d'une recherche supplémentaire par if index < len(my_list) .

Python encourage l'utilisation des exceptions, que vous manipulez est une phrase de Plongez dans Python . Votre exemple ne se contente pas de gérer l'exception (de manière élégante), au lieu de la laisser se produire. passer en silence En outre, l'exception ne se produit que dans le fichier exceptionnel cas d'index non trouvé (d'où le mot exception !).


code plus propre

La documentation officielle de Python mentionne EAFP : Il est plus facile de demander le pardon que la permission. y Rob Knight note que détecter les erreurs plutôt que de les éviter peut donner lieu à un code plus propre et plus facile à lire. Son exemple le dit ainsi :

Pire (LBYL "regarde avant de sauter") :

#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit():
    return None
elif len(s) > 10:    #too many digits for int conversion
    return None
else:
    return int(s)

Meilleur (EAFP : Il est plus facile de demander le pardon que la permission) :

try:
    return int(s)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None

0 votes

if index in mylist teste si l'index est un élément de mylist, et non un index possible. Vous voudriez if index < len(mylist) à la place.

1 votes

C'est logique, mais où puis-je trouver la documentation qui indique clairement les exceptions possibles pour la fonction int(). docs.python.org/3/library/functions.html#int Je ne parviens pas à trouver cette information ici.

0 votes

En face, vous pouvez ajouter ce cas (de éteint. doc ) à votre réponse, alors que vous devriez préférer if/else que try/catch

21voto

duskwuff Points 69245

Dans ce cas particulier, vous devriez utiliser quelque chose d'entièrement différent :

x = myDict.get("ABC", "NO_ABC")

En général, cependant : si vous vous attendez à ce que le test échoue fréquemment, utilisez if . Si le test est coûteux par rapport au simple fait d'essayer l'opération et d'attraper l'exception en cas d'échec, utilisez l'option try . Si aucune de ces conditions ne s'applique, choisissez ce qui se lit le mieux.

2 votes

+1 pour l'explication sous l'exemple de code, qui est juste.

4 votes

Je pense qu'il est assez clair que ce n'est pas ce qu'il demandait, et il a maintenant édité son message pour le rendre encore plus clair.

8voto

Amber Points 159296

S'il est trivial de vérifier si quelque chose va échouer avant de le faire, vous devriez probablement le favoriser. Après tout, la construction d'exceptions (y compris leurs traces associées) prend du temps.

Les exceptions doivent être utilisées pour :

  1. des choses qui sont inattendues, ou...
  2. les choses pour lesquelles vous devez sauter plus d'un niveau de logique (par exemple, lorsqu'une break ne vous mène pas assez loin), ou...
  3. les choses pour lesquelles vous ne savez pas exactement ce qui va gérer l'exception à l'avance, ou...
  4. les choses pour lesquelles la vérification préalable de l'échec est coûteuse (par rapport à la simple tentative de l'opération)

Notez que souvent, la vraie réponse est "ni l'un ni l'autre" - par exemple, dans votre premier exemple, ce que vous avez réellement devrait est simplement d'utiliser .get() pour fournir une valeur par défaut :

x = myDict.get('ABC', 'NO_ABC')

0 votes

Sauf que if 'ABC' in myDict: x = myDict['ABC']; else: x = 'NO_ABC' est en fait souvent plus rapide que l'utilisation de get malheureusement. Je ne dis pas que c'est le critère le plus important, mais c'est quelque chose dont il faut être conscient.

0 votes

@agf : Il est préférable d'écrire un code clair et concis. Si quelque chose doit être optimisé plus tard, il est facile de revenir en arrière et de le réécrire, mais c2.com/cgi/wiki?PrematureOptimization

0 votes

I conozca ça ; mon point de vue était que if / else y try / except peuvent avoir leur place même lorsqu'il existe des alternatives spécifiques à chaque cas car ils ont des caractéristiques de performance différentes.

6voto

Peter Points 121

Comme le mentionnent les autres messages, cela dépend de la situation. Il y a quelques dangers à utiliser try/except au lieu de vérifier la validité de vos données à l'avance, surtout lorsque vous l'utilisez sur des projets plus importants.

  • Le code dans le bloc d'essai peut avoir la possibilité de faire toutes sortes de dégâts avant que l'exception ne soit détectée - si vous vérifiez de manière proactive à l'avance avec une instruction if, vous pouvez éviter cela.
  • Si le code appelé dans votre bloc d'essai lève un type d'exception commun, comme TypeError ou ValueError, il se peut que vous n'attrapiez pas réellement l'exception que vous vous attendiez à attraper - il se peut que ce soit autre chose qui lève la même classe d'exception avant ou après avoir atteint la ligne où votre exception peut être levée.

par exemple, supposez que vous ayez :

try:
    x = my_list[index_list[3]]
except IndexError:
    x = 'NO_ABC'

L'IndexError ne dit pas si elle s'est produite en essayant d'obtenir un élément de index_list ou de my_list.

4voto

Karl Knechtel Points 24349

L'utilisation d'un try au lieu d'un if doit-elle être interprétée comme une erreur passant silencieusement ? Et si c'est le cas, est-ce que vous la réduisez explicitement au silence en l'utilisant de cette façon, ce qui la rend acceptable ?

Utilisation de try c'est reconnaître qu'une erreur peut passer, ce qui est le contraire de la faire passer silencieusement. Utilisation de except fait qu'il ne passe pas du tout.

Utilisation de try: except: est préférable dans les cas où if: else: La logique est plus compliquée. Le simple est mieux que le complexe ; le complexe est mieux que le compliqué ; et il est plus facile de demander le pardon que la permission.

L'avertissement "les erreurs ne devraient jamais passer silencieusement" concerne le cas où le code pourrait lever une exception que vous connaissez, et où votre conception admet la possibilité, mais vous n'avez pas conçu un moyen de traiter l'exception. Silencier explicitement une erreur, à mon avis, serait de faire quelque chose comme pass dans un except ce qui ne devrait être fait que si l'on comprend que "ne rien faire" est vraiment le traitement correct de l'erreur dans cette situation particulière. (C'est l'une des rares fois où j'ai l'impression qu'un commentaire dans un code bien écrit est probablement vraiment nécessaire).

Cependant, dans votre exemple particulier, aucun des deux n'est approprié :

x = myDict.get('ABC', 'NO_ABC')

La raison pour laquelle tout le monde le souligne - même si vous reconnaissez votre désir de comprendre en général, et votre incapacité à trouver un meilleur exemple - est que des pas de côté équivalents existent en fait dans un grand nombre de cas, et que les rechercher est la première étape de la résolution du problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X