Sous-sections
8. Erreurs et Exceptions
Jusqu'ici nous avons à peine mentionné les messages d'erreur, mais si
vous avez essayé les exemples vous en avez certainement croisé. Il y a
(au moins) deux types distincts d'erreurs: les erreurs de
syntaxe et les exceptions.
8.1 Erreurs de Syntaxe
Les erreurs de syntaxe, ou erreurs d'interprétation, sont peut-être
les formes de messages d'erreur les plus courantes que vous
rencontrerez pendant votre apprentissage de Python:
>>> while 1 print 'Bonjour'
File "<stdin>", line 1
while 1 print 'Bonjour'
^
SyntaxError: invalid syntax
L'interpréteur affiche la ligne où l'erreur a eu lieu, et une petite
`flèche' qui marque le premier point de la ligne où l'erreur a été
détectée. L'erreur est causée par le (ou du moins détectée au) lexème
qui précède la flèche: dans l'exemple, l'erreur est détectée au
mot-clé print, vu qu'il manque un deux-points
(":") juste avant. Un nom et un numéro de ligne de fichier
sont aussi donnés pour que vous sachiez où aller regarder si les
commandes proviennent d'un script.
8.2 Exceptions
Même lorsqu'une instruction ou une expression est syntaxiquement correcte, elle
peut provoquer une erreur lorsqu'on essaye de l'exécuter.
Les erreurs détectées à l'exécution sont appelées exceptions et ne
sont pas fatales: vous allez bientôt apprendre à les gérer dans des programmes
Python. Néanmoins, la plupart des exceptions n'est pas gérée par un programme
et entraîne des messages d'erreur comme ci-dessous:
>>> 10 * (1/0)
Traceback (innermost last):
File "<stdin>", line 1
ZeroDivisionError: integer division or modulo
>>> 4 + spam*3
Traceback (innermost last):
File "<stdin>", line 1
NameError: spam
>>> '2' + 2
Traceback (innermost last):
File "<stdin>", line 1
TypeError: illegal argument type for built-in operation
La dernière ligne du message d'erreur indique ce qui s'est passé.
Les exceptions peuvent être de plusieurs types, le type est écrit dans
le message: dans l'exemple, les types sont
ZeroDivisionError (erreur de division par zéro),
NameError (erreur de nom) et TypeError (erreur
de type).
La chaîne de caractères affichée comme type de l'exception est le nom
intégré pour l'exception qui a eu lieu. C'est le cas pour
toutes les exceptions intégrées, mais pas forcément pour les
exceptions définies par l'utilisateur (même si c'est une convention
utile). Les noms des exceptions standard sont des identifiants intégrés
(et non des mots-clés réservés).
Le reste de la ligne contient des détails, dont l'interprétation dépend du
type de l'exception.
La partie précédant le message d'erreur affiche le contexte dans lequel
l'exception a eu lieu, sous forme de trace de la pile.
En général, elle contient une trace de pile avec des lignes de
code source; toutefois, les lignes lues depuis l'entrée standard ne
seront pas affichées.
La Library Reference donne la liste des exceptions intégrées
et leur signification.
8.3 Gestion des Exceptions
Il est possible d'écrire des programmes qui prennent en charge des
exceptions spécifiques. Regardez l'exemple suivant, qui affiche une
table des inverses de quelques nombres à virgule flottante:
>>> while 1:
... try:
... x = int(raw_input("Veuillez entrer un nombre: "))
... break
... except ValueError:
... print "Aille! Ce n'était pas un nombre valide. Essayez encore..."
...
L'instruction try fonctionne ainsi:
- D'abord, la clause d'essai (clause try: les
instructions entre les mots-clés try et except)
est exécutée.
- S'il ne se produit pas d'exception, la clause d'exception (clause except) est ignorée, et l'exécution du try est
terminée.
- Si une exception se produit à un moment de l'exécution de la clause d'essai,
le reste de la clause try est ignoré. Puis si son type correspond à l'exception
donnée après le mot-clé except, la clause except est exécutée,
puis l'exécution reprend après l'instruction try.
- Si une exception se produit qui ne correspond pas à l'exception donnée
dans la clause except, elle est renvoyée aux instructions try
extérieures; s'il n'y a pas de prise en charge, il s'agit d'une
exception non gérée et l'exécution est arrêtée avec un message, comme
vu précédemment.
Une instruction try peut avoir plus d'une clause d'exception,
de façon à définir des gestionnaires d'exception différents pour des exceptions différentes.
Au plus une clause d'exception sera exécutée.
Dans une clause d'exception ne seront gérées que les exceptions
survenant dans la clause d'essai correspondante, et non pas celles
provenant d'autres clauses d'exception.
Une clause d'exception peut nommer plusieurs exceptions dans une liste
parenthésée, par exemple:
... except (RuntimeError, TypeError, NameError):
... pass
La dernière clause d'exception peut omettre le(s) nom(s) d'exception,
et sert alors de passe-partout. Utilisez ceci avec une précaution extrême:
il est facile de cacher de cette façon une vraie erreur de programmation!
import string, sys
try:
f = open('monfichier.txt')
c = f.readline()
i = int(string.strip(c))
except IOError, (errno, strerror):
print "Erreur(s) E/S: c" (errno, strerror)
except ValueError:
print "N'a pas pu convertir la donnée en entier."
except:
print "Erreur non prévue:", sys.exc_info()[0]
raise
L'instruction try...except admet une clause par défaut
(clause else) qui doit suivre toutes les clauses d'exception. Elle est
utile pour placer le code qui doit être exécuté si la clause d'essai ne déclenche pas
d'exception. Par exemple:
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except IOError:
print 'impossible d'ouvrir', arg
else:
print arg, 'comporte', len(f.readlines()), 'lignes'
f.close()
L'utilisation de la clause else est meilleure que l'ajout
d'un code supplémentaire à la clause try parce qu'elle évite
d'intercepter de façon accidentelle une exception qui n'a pas été
déclenchée par le code qui est protégé par l'instruction try
... except.
Quand une exception survient, elle peut avoir une valeur associée,
appelée aussi l'argument de l'exception.
La présence et le type de l'argument dépendent du type de l'exception.
Pour les types d'exception qui ont un argument, la clause d'exception
peut spécifier une variable après le nom (ou la liste) d'exception(s)
qui recevra la valeur de l'argument, de la manière suivante:
>>> try:
... spam()
... except NameError, x:
... print 'nom', x, 'non défini'
...
nom spam non défini
Si une exception a un argument, celui-ci sera affiché dans la dernière
partie (`détail') du message pour une exception non gérée.
Les clauses d'exception ne prennent pas en charge uniquement les
exceptions qui surviennent dans la clause d'essai, mais aussi celles
qui surviennent dans les fonctions appelées (même de façon indirecte)
dans la clause d'essai.
Par exemple:
>>> def ceci_ne_marche_pas():
... x = 1/0
...
>>> try:
... ceci_ne_marche_pas()
... except ZeroDivisionError, detail:
... print 'Gestion d'erreur à l'exécution:', detail
...
Gestion d'erreur à l'exécution: integer division or modulo
8.4 Déclencher des Exceptions
L'instruction raise permet au programmeur de déclencher une exception.
Par exemple:
>>> raise NameError, 'Coucou'
Traceback (innermost last):
File "<stdin>", line 1
NameError: Coucou
Le premier argument de raise nomme l'exception qui
doit être déclenchée. Le second argument (optionnel) spécifie
l'argument de l'exception.
8.5 Exceptions Définies par l'Utilisateur
Les programmes peuvent nommer leurs propres exceptions en affectant
une chaîne de caractères à une variable.
Par exemple.
>>> mon_exc = 'mon_exc'
>>> try:
... raise mon_exc, 2*2
... except mon_exc, val:
... print 'Mon exception a été déclenchée, valeur:', val
...
Mon exception a été déclenchée, valeur: 4
>>> raise mon_exc, 1
Traceback (innermost last):
File "<stdin>", line 1
mon_exc: 1
Plusieurs modules standard s'en servent pour rapporter les erreurs qui
peuvent survenir dans les fonctions qu'ils définissent.
Plus d'informations au sujet des classes sont données dans le chapitre
9, ``Classes.''
8.6 Définir les Actions de Nettoyage
L'instruction try admet une autre clause optionnelle qui
permet de définir les actions de nettoyage qui doivent être exécutées
impérativement. Par exemple:
>>> try:
... raise KeyboardInterrupt
... finally:
... print 'Adieu, monde!'
...
Adieu, monde!
Traceback (innermost last):
File "<stdin>", line 2
KeyboardInterrupt
Une clause de finalisation (clause finally) est exécutée
qu'une exception ait eu lieu ou non dans la clause d'essai. Si une
exception a été déclenchée, elle est déclenchée à nouveau après
l'exécution de la clause de finalisation. La clause de finalisation
est aussi exécutée ``en sortant'' lorsque l'instruction try
est interrompue par les instructions break ou
return.
Une instruction try doit avoir ou bien une ou plusieurs
clauses d'exception, ou bien une clause de finalisation, mais pas les
deux.
See About this document... for information on suggesting changes.
|