Pourquoi «except: pass» est une mauvaise pratique de programmation?

325

Je vois souvent des commentaires sur d'autres questions Stack Overflow sur la façon dont l'utilisation de except: passest découragée. Pourquoi est-ce mauvais? Parfois, je me fiche des erreurs et je veux simplement continuer avec le code.

try:
    something
except:
    pass

Pourquoi est-ce except: passmauvais d' utiliser un bloc? Qu'est-ce qui le rend mauvais? Est-ce le fait que je suis passsur une erreur ou que j'ai exceptune erreur?

Vador
la source
1
C'est le moins que je puisse vous suggérer de le faire pour que vous SAVIEZ quels problèmes vous ignorez. Utilisez le loggingmodule au niveau DEBUG pour éviter leur diffusion en production, mais gardez-les disponibles en développement.
pcurry

Réponses:

346

Comme vous l'avez bien deviné, il y a deux côtés: intercepter toute erreur en ne spécifiant aucun type d'exception après except, et simplement le passer sans prendre aucune action.

Mon explication est «un peu» plus longue - donc tl; dr, cela se résume à ceci:

  1. N'attrapez aucune erreur . Spécifiez toujours les exceptions à partir desquelles vous êtes prêt à récupérer et interceptez uniquement celles-ci.
  2. Essayez d'éviter de passer à l'exception des blocs . À moins que cela ne soit explicitement souhaité, ce n'est généralement pas un bon signe.

Mais entrons dans les détails:

Ne détectez aucune erreur

Lorsque vous utilisez un trybloc, vous le faites généralement parce que vous savez qu'il y a une chance qu'une exception soit levée. En tant que tel, vous avez également déjà une idée approximative de ce qui peut se casser et de quelle exception peut être levée. Dans de tels cas, vous interceptez une exception car vous pouvez vous en remettre positivement . Cela signifie que vous êtes prêt pour l'exception et que vous avez un plan alternatif que vous suivrez en cas d'exception.

Par exemple, lorsque vous demandez à l'utilisateur de saisir un nombre, vous pouvez convertir l'entrée en utilisant int()ce qui pourrait élever un ValueError. Vous pouvez facilement récupérer cela en demandant simplement à l'utilisateur de réessayer, donc attraper le ValueErroret l'inviter à nouveau serait un plan approprié. Un autre exemple serait si vous voulez lire une configuration d'un fichier et que ce fichier n'existe pas. Puisqu'il s'agit d'un fichier de configuration, vous pouvez avoir une configuration par défaut en tant que solution de secours, donc le fichier n'est pas exactement nécessaire. Donc, attraper un FileNotFoundErroret simplement appliquer la configuration par défaut serait un bon plan ici. Maintenant, dans ces deux cas, nous avons une exception très spécifique à laquelle nous nous attendons et avons un plan tout aussi spécifique pour s'en remettre. Ainsi, dans chaque cas, nous expliquons uniquement except que certains exception.

Cependant, si nous devions tout attraper , alors - en plus des exceptions dont nous sommes prêts à nous remettre - il y a aussi une chance que nous obtenions des exceptions auxquelles nous ne nous attendions pas et que nous ne pouvons en effet pas récupérer; ou ne devrait pas récupérer.

Prenons l'exemple du fichier de configuration ci-dessus. En cas de fichier manquant, nous venons d'appliquer notre configuration par défaut, et nous pourrions décider ultérieurement de sauvegarder automatiquement la configuration (donc la prochaine fois, le fichier existera). Imaginez maintenant que nous obtenions un IsADirectoryErrorou unPermissionErrorau lieu. Dans de tels cas, nous ne voulons probablement pas continuer; nous pourrions toujours appliquer notre configuration par défaut, mais nous ne pourrons plus enregistrer le fichier ultérieurement. Et il est probable que l'utilisateur voulait également avoir une configuration personnalisée, donc l'utilisation des valeurs par défaut n'est probablement pas souhaitée. Nous voudrions donc en informer immédiatement l'utilisateur, et probablement aussi interrompre l'exécution du programme. Mais ce n'est pas quelque chose que nous voulons faire quelque part au fond d'une petite partie de code; c'est quelque chose d'importance au niveau de l'application, donc cela devrait être géré en haut - alors laissez l'exception bouillonner.

Un autre exemple simple est également mentionné dans le document sur les idiomes Python 2 . Ici, une simple faute de frappe existe dans le code qui la fait casser. Parce que nous interceptons toutes les exceptions, nous interceptons également NameErrors et SyntaxErrors . Les deux sont des erreurs qui nous arrivent à tous lors de la programmation; et les deux sont des erreurs que nous ne voulons absolument pas inclure lors de l'expédition du code. Mais parce que nous les avons également capturés, nous ne saurons même pas qu'ils se sont produits là-bas et perdons toute aide pour le déboguer correctement.

Mais il existe également des exceptions plus dangereuses auxquelles nous ne sommes probablement pas préparés. Par exemple, SystemError est généralement quelque chose qui se produit rarement et que nous ne pouvons pas vraiment planifier; cela signifie qu'il se passe quelque chose de plus compliqué, quelque chose qui nous empêche probablement de poursuivre la tâche actuelle.

Dans tous les cas, il est très peu probable que vous soyez prêt à tout dans une petite partie du code, c'est donc vraiment là que vous ne devez intercepter que les exceptions pour lesquelles vous êtes préparé. Certaines personnes suggèrent au moins d'attraper Exceptioncar cela n'inclura pas des choses comme SystemExitet KeyboardInterruptqui, par conception, doivent mettre fin à votre application, mais je dirais que c'est encore beaucoup trop peu spécifique. Il n'y a qu'un seul endroit où j'accepte personnellement la capture Exceptionou tout autreexception, et qui se trouve dans un seul gestionnaire d'exceptions global au niveau de l'application qui a pour seul but de consigner toute exception pour laquelle nous n'étions pas préparés. De cette façon, nous pouvons toujours conserver autant d'informations sur les exceptions inattendues, que nous pouvons ensuite utiliser pour étendre notre code pour les gérer explicitement (si nous pouvons les récupérer) ou - en cas de bogue - pour créer des cas de test pour nous assurer cela ne se reproduira plus. Mais bien sûr, cela ne fonctionne que si nous ne détectons que les exceptions que nous attendions déjà, donc celles auxquelles nous ne nous attendions pas vont naturellement bouillonner.

Essayez d'éviter de passer à l'exception des blocs

Lors de la capture explicite d'une petite sélection d'exceptions spécifiques, il existe de nombreuses situations dans lesquelles nous serons bien en ne faisant simplement rien. Dans de tels cas, le simple fait d'avoir except SomeSpecificException: passest très bien. La plupart du temps cependant, ce n'est pas le cas car nous avons probablement besoin d'un code lié au processus de récupération (comme mentionné ci-dessus). Cela peut être par exemple quelque chose qui recommence l'action, ou pour configurer une valeur par défaut à la place.

Si ce n'est pas le cas, par exemple parce que notre code est déjà structuré pour se répéter jusqu'à ce qu'il réussisse, alors le simple passage est suffisant. En prenant notre exemple ci-dessus, nous pourrions vouloir demander à l'utilisateur d'entrer un nombre. Parce que nous savons que les utilisateurs aiment ne pas faire ce que nous leur demandons, nous pourrions simplement le mettre en boucle en premier lieu, afin que cela ressemble à ceci:

def askForNumber ():
    while True:
        try:
            return int(input('Please enter a number: '))
        except ValueError:
            pass

Parce que nous continuons d'essayer jusqu'à ce qu'aucune exception ne soit levée, nous n'avons pas besoin de faire quoi que ce soit de spécial dans le bloc except, donc c'est très bien. Mais bien sûr, on pourrait faire valoir que nous voulons au moins montrer à l'utilisateur un message d'erreur pour lui dire pourquoi il doit répéter l'entrée.

Dans de nombreux autres cas cependant, le simple fait de passer exceptun signe indique que nous n'étions pas vraiment préparés à l'exception que nous attrapons. À moins que ces exceptions ne soient simples (comme ValueErrorou TypeError) et que la raison pour laquelle nous pouvons passer soit évidente, essayez d'éviter simplement de passer. S'il n'y a vraiment rien à faire (et vous en êtes absolument sûr), pensez à ajouter un commentaire expliquant pourquoi c'est le cas; sinon, développez le bloc except pour inclure réellement du code de récupération.

except: pass

Le pire contrevenant est la combinaison des deux. Cela signifie que nous détectons volontiers toute erreur bien que nous ne soyons absolument pas préparés à cela et que nous ne fassions rien non plus. Vous souhaitez au moins enregistrer l'erreur et également la relancer pour terminer l'application (il est peu probable que vous puissiez continuer comme d'habitude après une MemoryError). Le simple fait de passer ne gardera pas seulement l'application un peu vivante (selon l'endroit où vous attrapez bien sûr), mais jettera également toutes les informations, ce qui rendra impossible de découvrir l'erreur - ce qui est particulièrement vrai si vous n'êtes pas celui qui la découvre.


Donc, l'essentiel est le suivant: n'attrapez que les exceptions auxquelles vous vous attendez vraiment et que vous êtes prêt à récupérer; tous les autres sont probablement soit des erreurs que vous devriez corriger, soit quelque chose auquel vous n'êtes pas préparé de toute façon. Passer des exceptions spécifiques est très bien si vous n'avez vraiment pas besoin de faire quelque chose à leur sujet. Dans tous les autres cas, c'est juste un signe de présomption et d'être paresseux. Et vous voulez vraiment résoudre ce problème.

poussée
la source
1
Msgstr "Vous voulez au moins enregistrer l 'erreur et probablement la relancer pour terminer l' application". Pouvez-vous montrer comment "relancer" une exception pour la laisser continuer à bouillonner même après l'avoir capturée? Cela me semble utile d'ajouter des messages d'erreur personnalisés tout en laissant l'exception forcer l'application à quitter.
Gabriel Staples
1
Cela aide à clarifier: ils utilisent la couverture except, mais appellent ensuite raisesans argument pour continuer de laisser l'exception bouillonner, mettant fin à l'application. Je l'aime: ianbicking.org/blog/2007/09/re-raising-exceptions.html . Ressemble à une exception solide à la règle de ne pas utiliser la couverture except.
Gabriel Staples
1
@GabrielStaples Oui, une exception interceptée peut être renvoyée en utilisant raise. Cependant, vous ne feriez généralement cela que dans quelques emplacements de votre application pour enregistrer l'exception.
percez le
C'est super, évitez de passer à l'exception des blocs. Je dirais que faire tout ce qui semble plus compréhensible, surtout pour les autres. Obtenez un deuxième ensemble d'yeux python pour examiner votre code et voir s'ils remettent en question le bloc. La lisibilité est la clé.
radtek
262

Le principal problème ici est qu'il ignore toutes les erreurs: Mémoire insuffisante, le processeur brûle, l'utilisateur veut s'arrêter, le programme veut quitter, Jabberwocky tue les utilisateurs.

C'est beaucoup trop. Dans votre tête, vous pensez "je veux ignorer cette erreur de réseau". Si quelque chose d' inattendu se passe mal, alors votre code continue silencieusement et se brise de manière complètement imprévisible que personne ne peut déboguer.

C'est pourquoi vous devez vous limiter à ignorer spécifiquement seulement certaines erreurs et laisser le reste passer.

Aaron Digulla
la source
75

L'exécution de votre pseudo-code ne donne littéralement aucune erreur:

try:
    something
except:
    pass

comme s'il s'agissait d'un morceau de code parfaitement valide, au lieu de lancer a NameError. J'espère que ce n'est pas ce que tu veux.

YS-L
la source
51

Pourquoi «except: pass» est une mauvaise pratique de programmation?

Pourquoi est-ce mauvais?

try:
    something
except:
    pass

Cela intercepte toutes les exceptions possibles, y compris GeneratorExit, KeyboardInterruptet SystemExit- qui sont des exceptions que vous n'avez probablement pas l'intention d'attraper. C'est la même chose que d'attraperBaseException .

try:
    something
except BaseException:
    pass

Les anciennes versions de la documentation disent :

Étant donné que chaque erreur en Python déclenche une exception, en utilisant except: peut faire de nombreuses erreurs de programmation ressembler à des problèmes d'exécution, ce qui entrave le processus de débogage.

Hiérarchie des exceptions Python

Si vous interceptez une classe d'exception parent, vous interceptez également toutes leurs classes enfants. Il est beaucoup plus élégant de ne détecter que les exceptions que vous êtes prêt à gérer.

Voici la hiérarchie des exceptions Python 3 - voulez-vous vraiment les attraper tous ?:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
           +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Ne faites pas ça

Si vous utilisez cette forme de gestion des exceptions:

try:
    something
except: # don't just do a bare except!
    pass

Vous ne pourrez alors pas interrompre votre somethingbloc avec Ctrl-C. Votre programme ignorera toutes les exceptions possibles à l'intérieur dutry bloc de code.

Voici un autre exemple qui aura le même comportement indésirable:

except BaseException as e: # don't do this either - same as bare!
    logging.info(e)

Au lieu de cela, essayez de ne saisir que l'exception spécifique que vous savez que vous recherchez. Par exemple, si vous savez que vous pourriez obtenir une erreur de valeur lors d'une conversion:

try:
    foo = operation_that_includes_int(foo)
except ValueError as e:
    if fatal_condition(): # You can raise the exception if it's bad,
        logging.info(e)   # but if it's fatal every time,
        raise             # you probably should just not catch it.
    else:                 # Only catch exceptions you are prepared to handle.
        foo = 0           # Here we simply assign foo to 0 and continue. 

Explication supplémentaire avec un autre exemple

Vous le faites peut-être parce que vous êtes en train de gratter le Web et que UnicodeError , mais parce que vous avez utilisé la capture d'exception la plus large, votre code, qui peut avoir d'autres défauts fondamentaux, tentera de s'exécuter complètement, gaspillant la bande passante , temps de traitement, usure de votre équipement, manque de mémoire, collecte de données sur les déchets, etc.

Si d'autres personnes vous demandent de terminer pour pouvoir compter sur votre code, je comprends que je me sens obligé de tout gérer. Mais si vous êtes prêt à échouer bruyamment à mesure que vous vous développez, vous aurez la possibilité de corriger des problèmes qui ne pourraient apparaître que de manière intermittente, mais ce seraient des bogues coûteux à long terme.

Avec une gestion des erreurs plus précise, votre code peut être plus robuste.

Aaron Hall
la source
31
>>> import this

Le Zen de Python, par Tim Peters

Beau, c'est mieux que laid.
Explicite vaut mieux qu'implicite.
Simple, c'est mieux que complexe.
Complexe vaut mieux que compliqué.
L'appartement est meilleur que l'emboîtement.
Clairsemé vaut mieux que dense.
La lisibilité compte.
Les cas spéciaux ne sont pas assez spéciaux pour enfreindre les règles.
Bien que la praticité l'emporte sur la pureté.
Les erreurs ne doivent jamais passer silencieusement.
Sauf silence explicite.
Face à l'ambiguïté, refusez la tentation de deviner.
Il devrait y avoir une - et de préférence une seule - manière évidente de le faire.
Bien que cela ne soit pas évident au début, sauf si vous êtes néerlandais.
C'est mieux que jamais.
Bien que jamais ne soit souvent meilleur queright maintenant.
Si l'implémentation est difficile à expliquer, c'est une mauvaise idée.
Si la mise en œuvre est facile à expliquer, ce peut être une bonne idée.
Les espaces de noms sont une excellente idée de klaxon - faisons-en plus!

Alors, voici mon avis. Chaque fois que vous trouvez une erreur, vous devez faire quelque chose pour la gérer, c'est-à-dire l'écrire dans le fichier journal ou autre chose. Au moins, il vous informe qu'il y avait une erreur.

Booster
la source
64
-1 argument d'autorité ne fait pas expliquer quoi que ce soit. L'autorité peut être erronée.
Izkata
23
ce que @Izkata a écrit, ET, une ligne en dessous, la même autorité écrit: "Sauf explicitement réduit au silence", ce qui est exactement ce que sauf: pass fait.
Ofri Raviv
13
@OfriRaviv Non, l'erreur ne passe- t-elle pas implicitement ? Explicitement, il faudrait nommer l'erreur qui devrait passer silencieusement, c'est-à-dire être explicite à ce sujet . Ce n'est pas ce que sauf: pass fait.
Chelonian
24

Vous devez utiliser au moins except Exception:pour éviter d'attraper des exceptions système comme SystemExitou KeyboardInterrupt. Voici le lien vers les documents.

En général, vous devez définir explicitement les exceptions que vous souhaitez intercepter, pour éviter d'attraper des exceptions indésirables. Vous devez savoir quelles exceptions vous ignorez .

Tupteq
la source
13

Tout d'abord, il viole deux principes du Zen of Python :

  • Explicite vaut mieux qu'implicite
  • Les erreurs ne devraient jamais passer silencieusement

Cela signifie que vous faites intentionnellement passer votre erreur en silence. De plus, vous ne savez pas quelle erreur s'est exactement produite, carexcept: pass elle interceptera toute exception.

Deuxièmement, si nous essayons de nous éloigner du Zen de Python et de parler en termes de juste santé mentale, vous devez savoir que l'utilisation except:passvous laisse sans connaissance ni contrôle dans votre système. La règle d'or consiste à lever une exception, en cas d'erreur, et à prendre les mesures appropriées. Si vous ne savez pas à l'avance quelles actions celles-ci devraient être, enregistrez au moins l'erreur quelque part (et mieux relancez l'exception):

try:
    something
except:
    logger.exception('Something happened')

Mais, généralement, si vous essayez d'attraper une exception, vous faites probablement quelque chose de mal!

Alexander Zhukov
la source
2
... Sauf si explicitement réduit au silence, ce qui est le cas avec OP.
Hyperboreus
Je veux connaître votre solution. En fait, quand vraiment rien ne doit être fait, je ne fais que lister les erreurs dans except et faire des commentaires et écrire des journaux. Ensuite, passez.
Booster
2
@Hyperboreus, je ne pense pas, qu'attraper toutes et toutes les erreurs les fait explicitement taire, c'est-à-dire que vous ne savez même pas ce que vous attrapez.
Alexander Zhukov
13
"Parce qu'un gars le dit" n'est pas vraiment une réponse à un "Pourquoi?" question.
Sebastian Negraszus
12

La except:passconstruction fait essentiellement taire toutes les conditions exceptionnelles qui surviennent pendant l' try:exécution du code couvert par le bloc.

Ce qui rend cette mauvaise pratique, c'est que ce n'est généralement pas ce que vous voulez vraiment. Le plus souvent, une condition spécifique apparaît que vous voulez faire taire, et except:passc'est trop un instrument contondant. Il fera le travail, mais il masquera également d'autres conditions d'erreur que vous n'avez probablement pas prévues, mais que vous voudrez peut-être traiter d'une autre manière.

Ce qui rend cela particulièrement important en Python, c'est que par les idiomes de ce langage, les exceptions ne sont pas nécessairement des erreurs . Ils sont souvent utilisés de cette façon, bien sûr, comme dans la plupart des langues. Mais Python en particulier les a parfois utilisés pour implémenter un chemin de sortie alternatif à partir de certaines tâches de code qui ne fait pas vraiment partie du cas normal, mais qui est toujours connu pour apparaître de temps en temps et peut même être attendu dans la plupart des cas. SystemExita déjà été mentionné comme un ancien exemple, mais l'exemple le plus courant de nos jours peut être StopIteration. L'utilisation d'exceptions de cette façon a provoqué beaucoup de controverse, en particulier lorsque les itérateurs et les générateurs ont été introduits pour la première fois dans Python, mais finalement l'idée a prévalu.

The Spooniest
la source
12

La raison n ° 1 a déjà été indiquée - elle cache des erreurs auxquelles vous ne vous attendiez pas.

(# 2) - Cela rend votre code difficile à lire et à comprendre pour les autres. Si vous interceptez une FileNotFoundException lorsque vous essayez de lire un fichier, il est assez évident pour un autre développeur de savoir quelles fonctionnalités le bloc "catch" devrait avoir. Si vous ne spécifiez pas d'exception, vous avez besoin de commentaires supplémentaires pour expliquer ce que le bloc doit faire.

(# 3) - Il montre une programmation paresseuse. Si vous utilisez le try / catch générique, cela indique soit que vous ne comprenez pas les erreurs d'exécution possibles dans votre programme, soit que vous ne savez pas quelles exceptions sont possibles en Python. La détection d'une erreur spécifique montre que vous comprenez à la fois votre programme et la plage d'erreurs que Python lance. Il est plus probable que d'autres développeurs et réviseurs de code fassent confiance à votre travail.

Kevin
la source
12

Alors, quelle sortie ce code produit-il?

fruits = [ 'apple', 'pear', 'carrot', 'banana' ]

found = False
try:
     for i in range(len(fruit)):
         if fruits[i] == 'apple':
             found = true
except:
     pass

if found:
    print "Found an apple"
else:
    print "No apples in list"

Imaginez maintenant que le bloc try- exceptsoit des centaines de lignes d'appels vers une hiérarchie d'objets complexe, et soit lui-même appelé au milieu de l'arborescence des appels d'un grand programme. Lorsque le programme tourne mal, où commencez-vous à chercher?

Ian Harvey
la source
5
Euh, merci aux gens qui ont 'corrigé' cela, mais s'il vous plaît ne le faites pas - c'est intentionnellement faux, au sens de 'question d'entretien'. C'est peut-être plus subtil qu'il apparaisse d'abord - essayez-le. Mon point est que l'écrasement de «toutes» les exceptions, en particulier en Python, rend le débogage difficile, même dans une douzaine de lignes de code triviales.
Ian Harvey
11

En général, vous pouvez classer toute erreur / exception dans l'une des trois catégories suivantes :

  • Fatal : Ce n'est pas de votre faute, vous ne pouvez pas les empêcher, vous ne pouvez pas vous en remettre. Vous ne devez certainement pas les ignorer et continuer, et laisser votre programme dans un état inconnu. Laissez simplement l'erreur terminer votre programme, vous ne pouvez rien faire.

  • Boneheaded : Votre propre faute, probablement due à une erreur de surveillance, de bogue ou de programmation. Vous devez corriger le bogue. Encore une fois, vous ne devez certainement pas ignorer et continuer.

  • Exogène : vous pouvez vous attendre à ces erreurs dans des situations exceptionnelles, comme un fichier introuvable ou une connexion interrompue . Vous devez explicitement gérer ces erreurs, et uniquement celles-ci.

Dans tous les cas except: pass, votre programme ne restera que dans un état inconnu, où il peut causer plus de dégâts.

Daniel AA Pelsmaeker
la source
6

Autrement dit, si une exception ou une erreur est levée, quelque chose ne va pas. Ce n'est peut-être pas quelque chose de très mal, mais créer, lancer et intercepter des erreurs et des exceptions juste pour le plaisir d'utiliser des instructions goto n'est pas une bonne idée, et c'est rarement fait. 99% du temps, il y avait un problème quelque part.

Les problèmes doivent être traités. Tout comme c'est le cas dans la vie, dans la programmation, si vous laissez les problèmes tranquilles et essayez de les ignorer, ils ne disparaissent pas souvent d'eux-mêmes; au lieu de cela, ils grossissent et se multiplient. Pour éviter qu'un problème ne se développe sur vous et ne frappe à nouveau plus loin sur la route, vous 1) l'éliminez et nettoyez le désordre par la suite, ou 2) le contenez et nettoyez le désordre par la suite.

Ignorer les exceptions et les erreurs et les laisser comme cela est un bon moyen de subir des fuites de mémoire, des connexions de base de données exceptionnelles, des verrous inutiles sur les autorisations de fichiers, etc.

En de rares occasions, le problème est si minuscule, trivial et - en plus d'avoir besoin d'un bloc try ... catch - autonome , qu'il n'y a vraiment aucun gâchis à nettoyer par la suite. Ce sont les seules occasions où cette meilleure pratique ne s'applique pas nécessairement. D'après mon expérience, cela signifie généralement que tout ce que le code fait est fondamentalement mesquin et évitable, et quelque chose comme les tentatives de nouvelle tentative ou les messages spéciaux ne valent ni la complexité ni le maintien du fil.

Dans mon entreprise, la règle est de faire presque toujours quelque chose dans un bloc catch, et si vous ne faites rien, vous devez toujours placer un commentaire avec une très bonne raison. Vous ne devez jamais passer ou laisser un bloc d'arrêt vide quand il y a quelque chose à faire.

Panzercrisis
la source
6

À mon avis, les erreurs ont une raison d'apparaître, que mon son est stupide, mais c'est ainsi. Une bonne programmation ne soulève des erreurs que lorsque vous devez les gérer. Aussi, comme je l'ai lu il y a quelque temps, "la pass-Statement est une déclaration qui montre que le code sera inséré plus tard", donc si vous voulez avoir une instruction except vide, n'hésitez pas à le faire, mais pour un bon programme, il y aura être une partie manquante. parce que vous ne gérez pas les choses que vous devriez avoir. Les exceptions qui apparaissent vous permettent de corriger les données d'entrée ou de modifier la structure de vos données afin que ces exceptions ne se reproduisent pas (mais dans la plupart des cas (exceptions réseau, exceptions générales d'entrée), les exceptions indiquent que les parties suivantes du programme ne s'exécuteront pas correctement. Par exemple, une NetworkException peut indiquer une connexion réseau interrompue et le programme ne peut pas envoyer / recevoir de données dans les prochaines étapes du programme.

Mais l'utilisation d'un bloc de passe pour un seul bloc d'exception est valide, car vous différenciez toujours les types d'exceptions, donc si vous mettez tous les blocs d'exception en un, il n'est pas vide:

try:
    #code here
except Error1:
    #exception handle1

except Error2:
    #exception handle2
#and so on

peut être réécrit de cette façon:

try:
    #code here
except BaseException as e:
    if isinstance(e, Error1):
        #exception handle1

    elif isinstance(e, Error2):
        #exception handle2

    ...

    else:
        raise

Ainsi, même plusieurs blocs except avec des instructions de passage peuvent entraîner du code, dont la structure gère des types spéciaux d'exceptions.

Sirac
la source
4

Tous les commentaires soulevés jusqu'à présent sont valables. Dans la mesure du possible, vous devez spécifier exactement quelle exception vous souhaitez ignorer. Dans la mesure du possible, vous devez analyser la cause de l'exception et ignorer uniquement ce que vous vouliez ignorer, et non le reste. Si une exception provoque un "crash spectaculaire" de l'application, alors qu'il en soit ainsi, car il est beaucoup plus important de savoir que l'inattendu s'est produit lorsqu'il s'est produit, que de cacher que le problème s'est jamais produit.

Cela dit, ne prenez aucune pratique de programmation comme une priorité. C'est stupide. Il y a toujours le temps et le lieu pour faire ignorer toutes les exceptions.

Un autre exemple de principe idiot est l'utilisation de l' gotoopérateur. Quand j'étais à l'école, notre professeur nous a appris gotoopérateur juste pour mentionner que tu ne l'utiliseras jamais. Ne croyez pas que les gens vous disent que xyz ne devrait jamais être utilisé et qu'il ne peut y avoir de scénario quand il est utile. Il y en a toujours.

galets
la source
1
Le cas "goto" est stylistique et est une question d'opinion, alors que "except: pass" est généralement factuellement faux. Il suppose que si quelqu'un devait, par exemple, "tuer -TERM" votre processus à ce moment-là, il devrait l'ignorer. À tout le moins, c'est un mauvais comportement.
Score_Under
1
@Score_Under encore, il existe des cas où cela est approprié à utiliser. Par exemple, lorsqu'une fonction que vous appelez est supplémentaire, d'origine / auteur inconnu, n'affecte pas les fonctionnalités de base, mais si les plantages peuvent causer des problèmes. Je me rends compte que vous diriez que de tels appels devraient être correctement recherchés et analysés, mais dans la vie réelle, ce n'est pas toujours possible.
galets
Pourtant, si je veux mettre fin à votre processus, kill -9 ne devrait pas être la seule option fiable.
Score_Under
2

La gestion des erreurs est très importante dans la programmation. Vous devez montrer à l'utilisateur ce qui ne va pas. Dans très peu de cas, vous pouvez ignorer les erreurs. C'est une très mauvaise pratique de programmation.

fastcodejava
la source
2

Comme il n'a pas encore été mentionné, il est préférable d'utiliser un style contextlib.suppress:

with suppress(FileNotFoundError):
    os.remove('somefile.tmp')

Notez que dans l'exemple fourni, l'état du programme reste le même, que l'exception se produise ou non. C'est-à-dire, somefile.tmpdevient toujours inexistant.

Mateen Ulhaq
la source