Comment ignorer correctement les exceptions

777

Lorsque vous voulez simplement faire un essai, sauf sans gérer l'exception, comment faites-vous en Python?

Est-ce que la bonne façon de procéder est la suivante?

try:
    shutil.rmtree(path)
except:
    pass
Joan Venge
la source
10
Bizarre que personne ne l'ait mentionné jusqu'à présent (je l'ai fait dans ma réponse), mais pour cette fonction spécifique, vous pouvez simplement le faire shutil.rmtree(path, ignore_errors=True). Cependant, cela ne s'applique pas à la plupart des fonctions.
Aaron Hall
9
Lecture importante lorsque vous pensez à ignorer les exceptions: pourquoi «except: pass» est une mauvaise pratique de programmation?
poke
3
Imaginez faire cela dans la vraie vie. essayez: get_cash ('$ 1000') sauf: pass # meh, ça ira probablement bien
Grokodile
La vraie vie:try: rob() except: run()
PatrickT

Réponses:

1039
try:
    doSomething()
except: 
    pass

ou

try:
    doSomething()
except Exception: 
    pass

La différence est que le premier attrapera également KeyboardInterrupt, SystemExitet des trucs comme ça, qui sont dérivés directement de exceptions.BaseException, non exceptions.Exception.

Voir la documentation pour plus de détails:

vartec
la source
4
Notez que StopIteration et Warning héritent tous deux également d'Exception. Selon vos besoins, vous souhaiterez peut-être hériter de StandardError à la place.
Ben Blank
1
C'est vrai, mais si vous ne faites pas attention, vous pouvez rencontrer des bogues subtils (surtout si vous faites autre chose que de transmettre StopIteration).
Jason Baker, le
17
-1, try: shuti.rmtree(...) except: passsupprimera grossièrement toutes les erreurs (même si vous mal orthographié shutilrésultant en un NameError) - à tout le moinsexcept OSError:
dbr
44
Cette réponse, bien qu'informative, manque une information cruciale - vous ne devriez jamais attraper une exception de cette façon. Au lieu de cela, vous devriez toujours essayer d'attraper uniquement les exceptions qui vous intéressent, sinon vous aurez des cauchemars lors de la chasse aux bugs triviaux, cachés par vos "except" génériques. Voir la réponse de dbr pour plus d'informations. (Je sais que ce n'était pas la question d'origine - mais quiconque le recherche prendra simplement votre extrait de code et l'utilisera tel quel)
johndodo
139

Il est généralement considéré comme la meilleure pratique de ne détecter que les erreurs qui vous intéressent. Dans le cas, shutil.rmtreec'est probablement OSError:

>>> shutil.rmtree("/fake/dir")
Traceback (most recent call last):
    [...]
OSError: [Errno 2] No such file or directory: '/fake/dir'

Si vous voulez ignorer silencieusement cette erreur, vous feriez:

try:
    shutil.rmtree(path)
except OSError:
    pass

Pourquoi? Supposons que vous (en quelque sorte) transmettez accidentellement à la fonction un entier au lieu d'une chaîne, comme:

shutil.rmtree(2)

Cela donnera l'erreur "TypeError: coercing to Unicode: need string or buffer, int found" - vous ne voudrez probablement pas ignorer cela, ce qui peut être difficile à déboguer.

Si vous voulez vraiment ignorer toutes les erreurs, attrapez Exceptionplutôt qu'une simple except:déclaration. Encore une fois, pourquoi?

Ne pas spécifier d'exception intercepte toutes les exceptions, y compris l' SystemExitexception qui sys.exit()utilise par exemple :

>>> try:
...     sys.exit(1)
... except:
...     pass
... 
>>>

Comparez cela aux éléments suivants, qui se terminent correctement:

>>> try:
...     sys.exit(1)
... except Exception:
...     pass
... 
shell:~$ 

Si vous voulez écrire du code qui se comporte toujours mieux, l' OSErrorexception peut représenter diverses erreurs, mais dans l'exemple ci-dessus, nous voulons seulement ignorer Errno 2, donc nous pourrions être encore plus spécifiques:

import errno

try:
    shutil.rmtree(path)
except OSError as e:
    if e.errno != errno.ENOENT:
        # ignore "No such file or directory", but re-raise other errors
        raise
dbr
la source
1
shutil.rmtreen'est pas le meilleur exemple, car vous utiliseriez simplement ignore_errors=Truecette fonction ..
wim
113

Lorsque vous voulez simplement faire un essai de capture sans gérer l'exception, comment le faites-vous en Python?

Cela dépend de ce que vous entendez par «manipulation».

Si vous voulez l'attraper sans rien faire, le code que vous avez publié fonctionnera.

Si vous voulez dire que vous voulez agir sur une exception sans empêcher l'exception de remonter la pile, alors vous voulez quelque chose comme ceci:

try:
    do_something()
except:
    handle_exception()
    raise  #re-raise the exact same exception that was thrown
Jason Baker
la source
88

Je cite d'abord la réponse de Jack o'Connor de ce fil . Le fil référencé a été fermé donc j'écris ici:

"Il existe une nouvelle façon de faire cela à venir dans Python 3.4:

from contextlib import suppress

with suppress(Exception):
    # your code

Voici le commit qui l'a ajouté: http://hg.python.org/cpython/rev/406b47c64480

Et voici l'auteur, Raymond Hettinger, qui parle de cela et de toutes sortes d'autres points forts de Python: https://youtu.be/OSGv2VnC0go?t=43m23s

Mon ajout à cela est l'équivalent Python 2.7:

from contextlib import contextmanager

@contextmanager
def ignored(*exceptions):
    try:
        yield
    except exceptions:
        pass

Ensuite, vous l'utilisez comme dans Python 3.4:

with ignored(Exception):
    # your code
Jabba
la source
55

Pour être complet:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")

Notez également que vous pouvez capturer l'exception comme ceci:

>>> try:
...     this_fails()
... except ZeroDivisionError as err:
...     print("Handling run-time error:", err)

... et relancez l'exception comme ceci:

>>> try:
...     raise NameError('HiThere')
... except NameError:
...     print('An exception flew by!')
...     raise

... des exemples du tutoriel python .

cbare
la source
43

Comment ignorer correctement les exceptions?

Il existe plusieurs façons de procéder.

Cependant, le choix de l'exemple a une solution simple qui ne couvre pas le cas général.

Spécifique à l'exemple:

Au lieu de

try:
    shutil.rmtree(path)
except:
    pass

Faites ceci:

shutil.rmtree(path, ignore_errors=True)

Il s'agit d'un argument spécifique à shutil.rmtree. Vous pouvez voir l'aide à ce sujet en procédant comme suit, et vous verrez qu'il peut également permettre la fonctionnalité sur les erreurs.

>>> import shutil
>>> help(shutil.rmtree)

Étant donné que cela ne couvre que le cas étroit de l'exemple, je vais montrer plus en détail comment gérer cela si ces arguments de mots clés n'existaient pas.

Approche générale

Étant donné que ce qui précède ne couvre que le cas étroit de l'exemple, je vais montrer plus en détail comment gérer cela si ces arguments de mots clés n'existaient pas.

Nouveau dans Python 3.4:

Vous pouvez importer le suppressgestionnaire de contexte:

from contextlib import suppress

Mais ne supprimez que l'exception la plus spécifique:

with suppress(FileNotFoundError):
    shutil.rmtree(path)

Vous ignorerez silencieusement FileNotFoundError:

>>> with suppress(FileNotFoundError):
...     shutil.rmtree('bajkjbkdlsjfljsf')
... 
>>> 

De la documentation :

Comme pour tout autre mécanisme qui supprime complètement les exceptions, ce gestionnaire de contexte ne doit être utilisé que pour couvrir des erreurs très spécifiques lorsque la poursuite silencieuse de l'exécution du programme est la bonne chose à faire.

Notez que suppresset FileNotFoundErrorne sont disponibles qu'en Python 3.

Si vous souhaitez que votre code fonctionne également en Python 2, consultez la section suivante:

Python 2 & 3:

Lorsque vous voulez juste faire un essai / sauf sans gérer l'exception, comment faites-vous en Python?

Est-ce que la bonne façon de procéder est la suivante?

try :
    shutil.rmtree ( path )
except :
    pass

Pour le code compatible Python 2, passest la bonne façon d'avoir une déclaration qui est un no-op. Mais quand vous faites un nu except:, qui est la même chose que faire ce except BaseException:qui comprend GeneratorExit, KeyboardInterruptet SystemExit, en général, vous ne voulez pas attraper ces choses.

En fait, vous devez être aussi précis que possible pour nommer l'exception.

Voici une partie de la hiérarchie des exceptions Python (2) , et comme vous pouvez le voir, si vous interceptez des exceptions plus générales, vous pouvez masquer les problèmes auxquels vous ne vous attendiez pas:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
... and so on

Vous voulez probablement attraper une OSError ici, et peut-être que l'exception dont vous vous souciez est s'il n'y a pas de répertoire.

Nous pouvons obtenir ce numéro d'erreur spécifique dans la errnobibliothèque et relancer si nous ne l'avons pas:

import errno

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno == errno.ENOENT: # no such file or directory
        pass
    else: # we had an OSError we didn't expect, so reraise it
        raise 

Remarque, une augmentation nue déclenche l'exception d'origine, ce qui est probablement ce que vous voulez dans ce cas. Écrit de manière plus concise, car nous n'avons pas vraiment besoin de le faire explicitement passavec du code dans la gestion des exceptions:

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno != errno.ENOENT: # no such file or directory
        raise 
Aaron Hall
la source
11

Lorsque vous voulez simplement faire un essai de capture sans gérer l'exception, comment le faites-vous en Python?

Cela vous aidera à imprimer ce qu'est l'exception :( c.-à-d. Essayez d'attraper sans gérer l'exception et imprimez l'exception.)

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]
Irengbam Tilokchan Singh
la source
10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

Pour info la clause else peut aller après toutes les exceptions et ne sera exécutée que si le code de l'essai ne provoque pas d'exception.

MrChrisRodriguez
la source
1
Enfin une bonne explication elsedans ce contexte. Et d'ajouter que finallysera toujours courir après tout (ou pas exception).
not2qubit
5

J'avais besoin d'ignorer les erreurs dans plusieurs commandes et putain a fait l'affaire

import fuckit

@fuckit
def helper():
    print('before')
    1/0
    print('after1')
    1/0
    print('after2')

helper()
citynorman
la source
+1 parce que vous avez définitivement fait ma journée parce qu'à l'intérieur de ce code source, vous pouvez apprendre des choses extrêmement utiles comme la modification de la pile en direct
WBAR
3

En Python, nous gérons des exceptions similaires à d'autres langages, mais la différence est une différence de syntaxe, par exemple,

try:
    #Your code in which exception can occur
except <here we can put in a particular exception name>:
    # We can call that exception here also, like ZeroDivisionError()
    # now your code
# We can put in a finally block also
finally:
    # Your code...
Deepak Kumar «TRIÉ»
la source
-4

Je fais habituellement juste:

try:
    doSomething()
except:
    _ = ""
Dylan Strudwick
la source
3
Je vous suggère de remplacer _ = ""par pass.
Legorooj