Dois-je tester que if
quelque chose est valide ou simplement try
le faire et attraper l'exception?
- Existe-t-il une documentation solide indiquant qu'une solution est préférable?
- Est-ce qu'une manière 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 devraient jamais passer silencieusement.
À moins d'être explicitement réduit au silence.
L'utilisation de a try
au lieu de an doit-elle if
être interprétée comme une erreur passant silencieusement? Et si tel est le cas, est-ce que vous le faites taire explicitement en l'utilisant de cette manière, pour que cela fonctionne?
Je ne parle pas de situations où vous ne pouvez faire les choses que d'une seule manière; par exemple:
try:
import foo
except ImportError:
import baz
if index in mylist
teste si l'index est un élément de mylist, pas un index possible. Vous voudriezif index < len(mylist)
plutôt.if/else
quetry/catch
Dans ce cas particulier, vous devez utiliser tout autre chose:
En général, cependant: si vous pensez que le test échoue fréquemment, utilisez
if
. Si le test est coûteux par rapport au simple essai de l'opération et à la détection de l'exception en cas d'échec, utiliseztry
. Si aucune de ces conditions ne s'applique, optez pour ce qui se lit plus facilement.la source
Utiliser
try
etexcept
directement plutôt qu'à l'intérieur d'unif
garde doit toujours être fait s'il y a une possibilité de condition de concurrence. Par exemple, si vous voulez vous assurer qu'un répertoire existe, ne faites pas ceci:Si un autre thread ou processus crée le répertoire entre
isdir
etmkdir
, vous quitterez. À la place, faites ceci:Cela ne quittera que si le répertoire «foo» ne peut pas être créé.
la source
S'il est trivial de vérifier si quelque chose échouera avant de le faire, vous devriez probablement favoriser cela. Après tout, la construction d'exceptions (y compris leurs retraits associés) prend du temps.
Des exceptions doivent être utilisées pour:
break
ne vous mène pas assez loin), ou ...Notez que souvent, la vraie réponse est «ni l'un ni l'autre» - par exemple, dans votre premier exemple, ce que vous devriez vraiment faire est simplement d'utiliser
.get()
pour fournir une valeur par défaut:la source
if 'ABC' in myDict: x = myDict['ABC']; else: x = 'NO_ABC'
c'est en fait souvent plus rapide que l'utilisationget
, malheureusement. Ne pas dire que c'est le critère le plus important, mais c'est quelque chose dont il faut être conscient.if / else
ettry / except
peut avoir leur place même lorsqu'il existe des alternatives spécifiques à un cas parce qu'elles ont des caractéristiques de performance différentes..get()
est la recherche d'attributs et la surcharge des appels de fonctions au niveau Python; l'utilisation de mots-clés sur des éléments intégrés va fondamentalement à C. Je ne pense pas que cela deviendra trop rapide de si tôt. En ce qui concerneif
vs.try
, la méthode read dict.get () renvoie un pointeur contenant des informations sur les performances. Le rapport entre les résultats et les échecs est important (try
peut être plus rapide si la clé existe presque toujours), tout comme la taille du dictionnaire.Comme le mentionnent les autres articles, cela dépend de la situation. Il y a quelques dangers à utiliser try / sauf au lieu de vérifier la validité de vos données à l'avance, en particulier lorsque vous les utilisez sur des projets plus importants.
par exemple, supposons que vous ayez:
IndexError ne dit rien sur le fait de savoir si cela s'est produit lors de la tentative d'obtention d'un élément de index_list ou my_list.
la source
Utiliser,
try
c'est reconnaître qu'une erreur peut passer, ce qui est le contraire de la faire passer en silence. L'utilisationexcept
fait que ça ne passe pas du tout.L'utilisation
try: except:
est préférable dans les cas où laif: else:
logique est plus compliquée. Le simple vaut mieux que le complexe; complexe vaut mieux que compliqué; et il est plus facile de demander pardon que la permission.Ce dont "les erreurs ne devraient jamais passer en silence" est un avertissement, c'est le cas où le code pourrait déclencher une exception que vous connaissez, et où votre conception en admet la possibilité, mais vous n'avez pas conçu de manière à gérer l'exception. À mon avis, faire taire explicitement une erreur reviendrait à faire quelque chose comme
pass
dans unexcept
bloc, ce qui ne devrait être fait qu'en comprenant que "ne rien faire" est vraiment la bonne gestion des erreurs dans une 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, ni l'un ni l'autre n'est approprié:
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 mesures parallèles équivalentes existent en fait dans de nombreux cas, et les rechercher est la première étape pour résoudre le problème.
la source
Chaque fois que vous utilisez
try/except
pour contrôler le flux, posez-vous les questions suivantes:try
bloc réussit et quand il échoue?try
bloc?try
bloc lève l'exception?try
bloc change, votre flux de contrôle se comportera-t-il toujours comme prévu?Si la réponse à une ou plusieurs de ces questions est «non», il peut y avoir beaucoup de pardon à demander; très probablement de votre futur moi.
Un exemple. J'ai récemment vu du code dans un projet plus vaste qui ressemblait à ceci:
En parlant au programmeur, il s'est avéré que le flux de contrôle prévu était:
Cela a fonctionné car
foo
une requête de base de données a été effectuée et la requête serait réussie six
était un entier et lancer unProgrammingError
ifx
était une liste.L'utilisation
try/except
est un mauvais choix ici:ProgrammingError
n'indique pas le problème réel (quix
n'est pas un entier), ce qui rend difficile de voir ce qui se passe.ProgrammingError
est déclenché lors d'un appel à la base de données, ce qui fait perdre du temps. Les choses deviendraient vraiment horribles s'il s'avérait que celafoo
écrit quelque chose dans la base de données avant de lever une exception ou de modifier l'état d'un autre système.ProgrammingError
est levé uniquement quandx
est une liste d'entiers. Supposons par exemple qu'il y ait une faute de frappe dansfoo
la requête de base de données de. Cela pourrait également augmenter unProgrammingError
. La conséquence est quebar(x)
maintenant est également appelé quandx
est un entier. Cela pourrait soulever des exceptions cryptiques ou produire des résultats imprévisibles.try/except
bloc ajoute une exigence à toutes les futures implémentations defoo
. Chaque fois que nous changeonsfoo
, nous devons maintenant réfléchir à la façon dont il gère les listes et nous assurer qu'il génère une erreurProgrammingError
et pas, disons, uneAttributeError
erreur ou pas du tout.la source
Pour une signification générale, vous pouvez envisager de lire les expressions idiomatiques et anti-idiomatiques en Python: exceptions .
Dans votre cas particulier, comme d'autres l'ont indiqué, vous devez utiliser
dict.get()
:la source