Quand quelque chose tourne mal
Quand Python ne peut pas faire ce que vous demandez, il lève une exception : float("abc") lève ValueError, {}["x"] lève KeyError, 1 / 0 lève ZeroDivisionError, ouvrir un fichier absent lève FileNotFoundError. Si rien ne la traite, le programme s'arrête et affiche une trace (traceback), la chaîne d'appels qui y a mené, à lire de bas en haut. C'est le bon résultat pour un vrai bogue. Pour les problèmes prévisibles, comme un mauvais prix saisi par un utilisateur, on traite l'exception avec try et except.
# Handle an expected problem
def to_price(text):
try:
return float(text)
except ValueError:
return None
print(to_price("184.25")) # 184.25
print(to_price("abc")) # None
# An unhandled one stops the program with a traceback
# print(int("abc")) # ValueError: invalid literal for int()...N'intercepter que ce qu'on attend
Nommez le type d'exception : except ValueError:. Un except: nu ou except Exception: avale aussi des bogues que vous ne vouliez pas cacher, comme une TypeError causée par un None, et le programme continue avec de mauvaises données. Plusieurs types peuvent partager un gestionnaire, except (ValueError, KeyError):, ou en avoir chacun un. Python essaie les gestionnaires dans l'ordre et exécute le premier qui correspond. Vous pouvez garder l'erreur avec except ValueError as error: et l'examiner.
# Specific handlers, tried in order
def read_quantity(text):
try:
return int(text)
except ValueError as error:
print("not a whole number:", error)
return 0
except TypeError:
print("expected text, got something else")
return 0
print(read_quantity("200")) # 200
print(read_quantity("2.5")) # prints the message, then 0
print(read_quantity(None)) # prints the message, then 0else et finally
Deux parties facultatives complètent l'instruction. else: ne s'exécute que si le bloc try n'a rien levé, ce qui garde la ligne risquée courte et le code suivant hors de la protection. finally: s'exécute toujours, erreur ou non, même après un return : servez-vous-en pour le nettoyage. Souvent, un bloc with fait déjà le nettoyage à votre place, comme pour les fichiers.
# else runs on success, finally runs always
def describe(text):
try:
price = float(text)
except ValueError:
print("bad price")
else:
print("price is", price)
finally:
print("done with", repr(text))
describe("184.25")
# price is 184.25
# done with '184.25'
describe("abc")
# bad price
# done with 'abc'Lever vos propres erreurs
Une fonction à qui l'on donne une valeur inacceptable doit refuser bruyamment avec raise, et non renvoyer discrètement quelque chose de faux : raise ValueError("price must be positive"). Choisissez le type prédéfini adapté (ValueError pour un bon type mais une mauvaise valeur, TypeError pour un mauvais type) et écrivez un message qui dit ce qui n'allait pas. L'appelant décide alors s'il l'intercepte. Dans un bloc except, un raise nu relève l'erreur qu'on vient d'attraper, pratique quand on voulait seulement la consigner.
# Refuse bad input, let the caller decide
def parse_price(text):
price = float(text) # may raise ValueError itself
if not price > 0:
raise ValueError("price must be positive")
return price
for text in ["184.25", "-5", "abc"]:
try:
print(parse_price(text))
except ValueError as error:
print("rejected:", error)
# 184.25
# rejected: price must be positive
# rejected: could not convert string to float: 'abc'except qui ne fait rien (except: pass) transforme un plantage que vous auriez pu déboguer en chiffres faux et silencieux, ce qui est bien pire dans du code de trading. N'interceptez une erreur que là où vous connaissez une réponse raisonnable : valeur par défaut, élément ignoré, nouvelle tentative, ou signalement puis arrêt. Sinon, laissez-la remonter vers un endroit qui saura quoi faire.try/except SpecificError: traitez les problèmes attendus, rien de plus.elses'exécute si rien n'a été levé ;finallys'exécute toujours.raise ValueError("message")refuse clairement une entrée invalide.
À suivre : modules et imports, comment réutiliser le code de la bibliothèque standard et de vos propres fichiers.
Lab : ce qui est noté
- Convertir du texte sans planter avec
safe_float25 pts - Refuser un mauvais prix avec
parse_price25 pts - Ignorer les entrées invalides avec
first_valid_price25 pts - Gérer un fichier absent ou abîmé avec
read_quantity25 pts