Le reste de ce chapitre présentera spécifiquement le mécanisme d'exception intégré de Python. L'ensemble du mécanisme d'exception Python est construit conformément aux spécifications orientées objet, ce qui le rend flexible et extensible. Même si tout le monde n'est pas familiarisé avec la programmation orientée objet (POO), il n'est pas nécessaire d'apprendre la technologie orientée objet lors de l'utilisation d'exceptions.
Les exceptions sont des raise
objets générés automatiquement par les fonctions Python . Une fois que l'objet d'exception est généré, l' raise
instruction qui a provoqué l'exception modifie le mode d'exécution du programme Python, qui est différent du flux d'exécution normal. Au lieu de continuer à exécuter raise
l'instruction suivante ou d'exécuter l'instruction suivante après la génération de l'exception, il récupère la chaîne d'appels de fonction actuelle et trouve un gestionnaire capable de gérer l'exception actuelle. Si un gestionnaire d'exceptions est trouvé, il sera appelé et l'objet d'exception sera accessible pour plus d'informations. Si aucun gestionnaire d'exceptions approprié n'est trouvé, le programme abandonne et signale une erreur.
{Facile à demander et difficile à reconnaître!}
En général, l'approche de Python en matière de gestion des erreurs est différente des approches courantes dans des langages tels que Java. Ces langages reposent sur l'extraction autant que possible avant que l'erreur ne se produise, car la gestion de l'exception après que l'erreur se produit nécessite souvent une variété de coûts élevés. Cette approche a été introduite dans la première section de ce chapitre et est parfois appelée approche «Look Before You Leap» (LBYL).
Cependant, Python peut s'appuyer davantage sur des «exceptions» et traiter les erreurs après qu'elles se produisent. Bien que cette dépendance puisse sembler risquée, si «l'exception» peut être utilisée correctement, le code sera plus léger et plus lisible, et ne sera traité que lorsqu'une erreur se produit. Cette méthode de gestion des erreurs de style Python est souvent appelée «Plus facile à demander pardon que l'autorisation» (EAFP).
14.2.1 Types d'exceptions Python
Afin de refléter correctement la cause réelle de l'erreur ou la situation anormale qui doit être signalée, divers types d'objets anormaux peuvent être générés. Il existe de nombreux types d'objets d'exception fournis par Python 3.6:
BaseException
SystemExit
KeyboardInterrupt
GeneratorExit
Exception
StopIteration
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
BytesWarningException
ResourceWarning
Les objets d'exception de Python sont construits de manière hiérarchique, et l'indentation dans la liste d'exceptions ci-dessus illustre ce point. Comme indiqué au chapitre 10 __builtins__
, une liste alphabétique des objets d'exception peut être obtenue à partir du module.
Chaque exception est une classe Python, héritée de la classe d'exception parente. Mais si vous n'avez pas été exposé à la POO, ne vous inquiétez pas. Par exemple, IndexError
aussi des LookupError
classes et des Exception
classes (par héritage), et encore BaseException
.
Cette structure hiérarchique est intentionnelle, la plupart des exceptions sont héritées de Exception
, il est fortement recommandé que toutes les exceptions définies par l'utilisateur soient également des Exception
sous-classes et non des BaseException
sous-classes. La raison en est la suivante.
try:
# 执行一些异常操作
except Exception:
# 处理异常
{: -} Dans le code ci-dessus, vous pouvez toujours utiliser Ctrl + C pour suspendre try
l'exécution du bloc d'instructions sans provoquer de code de gestion des exceptions. Parce que l' KeyboardInterrupt
exception n'est pas Exception
une sous-classe.
Bien que l'explication de chaque exception puisse être trouvée dans la documentation, les exceptions les plus courantes peuvent être rapidement familiarisées avec la programmation pratique.
14.2.2 Lancer une exception
Des exceptions peuvent être levées par de nombreuses fonctions intégrées de Python:
>>> alist = [1, 2, 3]
>>> element = alist[7]
Traceback (innermost last):
File "<stdin>", line 1, in ?
IndexError: list index out of range
Le code de vérification d'erreurs intégré à Python détectera que la valeur d'index de la liste demandée à lire dans la deuxième ligne n'existe pas et lèvera IndexError
une exception. L'exception est toujours renvoyée à la couche supérieure, qui est l'interpréteur Python interactif, et l'interpréteur la gère en imprimant un message indiquant qu'une exception s'est produite.
Dans votre propre code, vous pouvez également utiliser des raise
instructions pour déclencher explicitement des exceptions. raise
La forme la plus élémentaire de la déclaration est la suivante:
raise exception(args)
exception(args)
Une partie créera un objet d'exception. Les paramètres du nouvel objet d'exception doivent généralement être des valeurs qui aident à déterminer la condition d'erreur, comme cela sera présenté plus tard. Une fois l'objet d'exception créé, il raise
sera généré la pile de fonctions Python, qui est raise
la fonction actuellement exécutée dans l' instruction. L'exception nouvellement créée sera levée vers le type de bloc de code de capture d'exception le plus proche de la pile. Si le bloc de code de capture d'exception correspondant n'est pas trouvé avant le niveau supérieur du programme, le programme s'arrêtera de s'exécuter et signalera une erreur. Dans la session interactive, le message d'erreur sera imprimé sur la console.
Veuillez essayer le code suivant:
>>> raise IndexError("Just kidding")
Traceback (innermost last):
File "<stdin>", line 1, in ?
IndexError: Just kidding
raise
Les messages générés ci-dessus semblent être similaires à tous les messages d'erreur d'index de liste Python précédents à première vue. Un examen plus attentif révélera que ce n'est pas le cas. L'erreur réelle n'est pas aussi grave que l'erreur précédente.
Les paramètres de chaîne sont souvent utilisés lors de la création d'exceptions. Si le premier paramètre est donné, la plupart des exceptions Python intégrées penseront que le paramètre est l'information à afficher pour expliquer l'événement qui s'est produit. Cependant, ce n'est pas toujours le cas, car chaque type d'exception a sa propre classe et les paramètres requis pour créer une exception de cette classe sont entièrement déterminés par la définition de la classe. En outre, les exceptions personnalisées créées par les programmeurs sont souvent utilisées à des fins autres que la gestion des erreurs, de sorte que les messages texte ne peuvent pas être utilisés comme paramètres.
14.2.3 Attraper et gérer les exceptions
Le but du mécanisme d'exception n'est pas d'arrêter le programme avec un message d'erreur. Il n'est jamais difficile d'implémenter la fonction d'abandon dans le programme. La particularité du mécanisme d'exception est qu'il n'empêche pas nécessairement l'exécution du programme. En définissant le code de gestion des exceptions approprié, vous pouvez vous assurer que les exceptions courantes n'entraîneront pas l'échec du programme. Il peut être possible d'afficher un message d'erreur ou d'autres méthodes à l'utilisateur, ou il peut être possible de résoudre le problème sans provoquer le blocage du programme.
Ce qui suit illustre la syntaxe de base de l'exception Python est interceptée et gérée, utilise try
et except
parfois par else
mot-clé:
try:
body
except exception_type1 as var1:
exception_code1
except exception_type2 as var2:
exception_code2
.
.
.
except:
default_exception_code
else:
else_body
finally:
finally_body
La première partie de l' try
instruction est exécutée body
. Si l'exécution réussit, c'est-à-dire que l' try
instruction n'a pas détecté d'exception levée, puis exécutez la else_body
partie et l' try
instruction est exécutée. Puisqu'il y a une finally
instruction ici , une partie sera exécutée ensuite finally_body
. Si une exception est try
levée, chaque except
clause sera recherchée à son tour pour trouver la clause qui correspond au type d'exception associé avec l'exception levée. Si une except
clause correspondante est trouvée , l'exception levée est affectée à la variable, le nom de la variable est donné après le type d'exception associé et except
le code de gestion des exceptions dans la clause correspondante est exécuté . Par exemple, si except exception_type as var:
cette ligne correspond à une exception levée exc
, une variable sera créée var
et la valeur except
sera var
affectée avant d' exécuter le code de gestion des exceptions de l' instruction exc
. var
Ce n'est pas nécessaire, cela ne peut qu'apparaître except exception_type
: de cette façon d'écrire, un type d'exception donné peut encore être intercepté, mais l'exception ne sera pas affectée à une variable.
Si aucune except
clause correspondante n'est trouvée , l' try
instruction ne peut pas gérer l'exception levée et l'exception continuera à être levée vers la couche supérieure de la chaîne d'appels de fonction, en attendant que la couche externe la try
gère.
try
La dernière except
clause de l'instruction ne peut spécifier aucun type d'exception, de sorte que tous les types d'exceptions seront traités. Pour certaines tâches de débogage et le prototypage très rapide, cette technique peut être pratique. Mais généralement, ce n'est pas une bonne pratique, toutes les erreurs sont except
couvertes par des clauses, ce qui peut rendre certains comportements du programme difficiles à comprendre.
try
Les else
clauses de l' instruction sont facultatives et sont rarement utilisées. La clause sera exécutée si et seulement si aucune erreur n'est générée lorsqu'une partie de l' try
instruction est exécutée.body
else
try
Déclaration finally
clause est également facultative, dans try
, except
, les else
pièces sont exécutées après la mise en œuvre. Si try
une exception est déclenchée dans le bloc et n'a été except
traitée par aucun bloc, finally
l'exception sera à nouveau déclenchée après l'exécution du bloc. Étant donné que le finally
bloc sera toujours exécuté, il peut fournir une opportunité d'ajouter du code de nettoyage des ressources via des opérations telles que la fermeture du fichier et la réinitialisation des variables une fois la gestion des exceptions terminée.
Pratique: attrapez l'exception et écrivez le code pour lire les deux nombres entrés par l'utilisateur et divisez le premier nombre par le deuxième nombre. Vérifiez et interceptez l'exception lorsque le deuxième nombre est 0 (
ZeroDivisionError
).
14.2.4 Personnaliser une nouvelle exception
Définir votre propre exception est très simple. Cela peut être fait avec les deux lignes de code suivantes:
class MyError(Exception):
pass
{: -} Le code ci-dessus crée une classe qui héritera de Exception
tout le contenu de la classe de base . Mais si vous ne souhaitez pas clarifier les détails, vous pouvez les ignorer.
Les exceptions ci-dessus peuvent être déclenchées, interceptées et gérées comme toute autre exception. Si un paramètre est donné et qu'il n'est pas capturé et traité, la valeur du paramètre sera imprimée à la fin des informations de trace:
>>> raise MyError("Some information about what went wrong")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyError: Some information about what went wrong
Bien entendu, les paramètres ci-dessus sont également accessibles dans le code de gestion des exceptions écrit par vous-même:
try:
raise MyError("Some information about what went wrong")
except MyError as error:
print("Situation:", error)
Le résultat de l'opération sera le suivant:
Situation: Some information about what went wrong
Si une exception est levée avec plusieurs paramètres, ces paramètres seront passés dans le code de gestion des exceptions sous la forme d'un tuple, et le tuple est accessible via error
les args
attributs de la variable :
try:
raise MyError("Some information", "my_filename", 3)
except MyError as error:
print("Situation: {0} with file {1}\n error code: {2}".format(
error.args[0],
error.args[1], error.args[2]))
Le résultat de l'opération sera le suivant:
Situation: Some information with file my_filename
error code: 3
Le type d'exception est une classe Python standard et hérite de la Exception
classe, il est donc relativement simple d'établir votre propre hiérarchie de types d'exceptions pour votre propre code. Lorsque vous lisez ce livre pour la première fois, vous n'avez pas besoin de vous soucier de ce processus. Après avoir lu le chapitre 15, vous pouvez revenir à tout moment. La création de votre propre exception est entièrement déterminée par les exigences. Si vous écrivez un petit programme qui ne peut générer que des erreurs ou exceptions uniques, utilisez la Exception
sous - classe de la classe comme décrit ci-dessus . Si vous écrivez une grande bibliothèque de codes de fonctions spécifiques à plusieurs fichiers (telle qu'une bibliothèque de prévisions météorologiques), vous pouvez envisager de définir une WeatherLibraryException
classe distincte nommée , puis définir toutes les différentes exceptions de la bibliothèque en tant que WeatherLibraryException
sous-classes.
Mesure de vitesse Sujet: Hypothèses
MyError
deException
classe «exception» héritées de la classe, je demandeexcept Exception as e
, etexcept MyError as e
quelle est la différence?
14.2.5 Utilisation des instructions assert pour déboguer des programmes
assert
La déclaration est raise
une forme spéciale de déclaration:
assert expression, argument
Si expression
le résultat du règlement est False
et que la variable système l' __debug__
est également True
, argument
une AssertionError
exception avec des paramètres facultatifs sera déclenchée . __debug__
La variable est par défaut True
. Démarrez l'interpréteur Python avec le paramètre -O
ou -OO
, ou définissez la variable système PYTHONOPTIMIZE
sur True
, que vous pouvez __debug__
définir sur False
. Des paramètres facultatifs argument
peuvent être utilisés pour placer assert
les informations d'explication.
Si __debug__
c'est le cas False
, le générateur de code ne assert
créera pas l'instruction de code. Dans la phase de développement, vous pouvez utiliser des assert
instructions pour coopérer avec des instructions de débogage pour tester le code. assert
L'instruction peut être stockée dans le code pour une utilisation future, et il n'y a pas de surcharge pendant l'utilisation normale:
>>> x = (1, 2, 3)
>>> assert len(x) > 5, "len(x) not > 5"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: len(x) not > 5
Question pratique: assert statement Veuillez écrire un programme simple qui permet à l'utilisateur de saisir un nombre et utiliser l'
assert
instruction pour provoquer une exception lorsque le nombre est 0. Tout d'abord, veuillez tester pour garantirassert
l'exécution de l'instruction, puis désactivez-la via les méthodes mentionnées dans cette sectionassert
.
14.2.6 Structure d'héritage anormale
Comme mentionné précédemment, l'exception de Python est une architecture en couches. Cette section donnera une introduction approfondie à cette architecture, y compris except
la signification de cette architecture pour savoir comment les clauses interceptent les exceptions.
Considérez le code suivant:
try:
body
except LookupError as error:
exception code
except IndexError as error:
exception code
Ici seront capturés IndexError
et LookupError
les deux exceptions. Il se trouve que IndexError
c'est LookupError
une sous-classe. Si elle est body
lancée IndexError
, l'erreur sera d'abord except LookupError as error:
détectée par la ligne " ". En raison de l' IndexError
héritage LookupError
, la première except
clause sera exécutée avec succès et la deuxième except
clause ne sera jamais utilisée car ses conditions de fonctionnement sont except
incluses dans la première clause.
Au contraire, except
il peut être judicieux d' inverser l'ordre des deux clauses. Ainsi, le processus dans la première clause IndexError
, la deuxième clause de traitement autre IndexError
que LookupError
.
14.2.7 Exemple: programme d'écriture sur disque écrit en Python
Cette section revient à l'exemple du programme de traitement de texte. Lors de l'écriture d'un document sur le disque, le programme doit vérifier si l'espace disque est insuffisant:
def save_to_file(filename) :
try:
save_text_to_file(filename)
save_formats_to_file(filename)
save_prefs_to_file(filename)
.
.
.
except IOError:
...处理错误...
def save_text_to_file(filename):
...调用底层函数来写入文本大小...
...调用底层函数来写入实际的文本数据...
.
.
.
Notez que le code de gestion des erreurs est très discret save_to_file
et qu'il est associé à une série d'appels d'écriture sur disque dans la fonction. Aucune de ces sous-fonctions d'écriture sur disque ne doit contenir de code de gestion des erreurs. Le programme sera plus facile à développer au début, et il est également très simple d'ajouter du code de gestion des erreurs plus tard. Les programmeurs font souvent cela, bien que cet ordre de mise en œuvre ne soit pas optimal.
Il est également intéressant de noter que le code ci-dessus ne répondra pas seulement à l'erreur de disque plein, mais répondra à toutes les IOError
exceptions. La fonction intégrée de Python lèvera automatiquement IOError
une exception chaque fois qu'elle ne peut pas terminer une demande d'E / S, quelle qu'en soit la raison . Cela peut suffire à répondre aux besoins, mais si vous souhaitez identifier individuellement le disque est plein, vous devez effectuer d'autres opérations. Vous pouvez except
vérifier la quantité d'espace libre dont dispose le disque dans le corps de l' instruction. Si l'espace disque est insuffisant, il est évident qu'un problème de disque plein s'est produit et doit except
être traité dans le corps de l' instruction. S'il ne s'agit pas d'un problème d'espace disque, except
le code dans le corps de l'instruction peut le jeter IOError
à la couche supérieure de la chaîne d'appels afin qu'il puisse être géré par d'autres except
corps d'instruction. Si cette solution ne suffit pas à résoudre le problème, vous pouvez également effectuer un traitement plus extrême, par exemple, trouver le code source C de la fonction d'écriture sur disque Python et lever une DiskFull
exception personnalisée si nécessaire . Cette dernière solution n'est pas recommandée, mais il est logique de savoir que cette possibilité existe lorsque cela est nécessaire.
14.2.8 Exemple: anomalie lors d'un calcul normal
L'utilisation la plus courante des exceptions est de gérer les erreurs, mais elles peuvent également être très utiles dans des situations qui devraient être considérées comme des calculs normaux. Imaginez les problèmes qui peuvent être rencontrés dans la mise en œuvre de tableurs. Comme la plupart des feuilles de calcul, le programme doit être capable d'effectuer des opérations arithmétiques impliquant plusieurs cellules, et il doit également permettre aux cellules de contenir des valeurs non numériques. Dans ce type d'application, le contenu des cellules vides rencontrées lors des calculs numériques peut être considéré comme des 0
valeurs. Les cellules contenant toute autre chaîne non numérique peuvent être considérées comme non valides et exprimées sous forme de None
valeurs Python . Tout calcul impliquant des valeurs non valides doit renvoyer des valeurs non valides.
Commençons par écrire une fonction pour évaluer la chaîne dans une cellule de feuille de calcul et renvoyer la valeur appropriée:
def cell_value(string):
try:
return float(string)
except ValueError:
if string == "":
return 0
else:
return None
Les capacités de gestion des exceptions de Python rendent cette fonction très simple à écrire. Dans le try
bloc, la chaîne de la cellule est float
convertie en un nombre avec une fonction intégrée et le résultat est renvoyé. Si la chaîne de paramètres ne peut pas être convertie en nombre, la float
fonction lève ValueError
une exception. Ensuite, le code de gestion des exceptions interceptera l'exception et retournera 0
ou None
, selon que la chaîne de paramètre est une chaîne vide.
Parfois, il peut être nécessaire None
de traiter la valeur lors de l'évaluation.L'étape suivante consiste à résoudre ce problème. Dans un langage de programmation sans mécanisme d'exception, la solution classique consiste à définir un ensemble de fonctions d'évaluation arithmétique personnalisées, à vérifier si les paramètres sont valides None
, puis à utiliser ces fonctions personnalisées pour remplacer les fonctions intégrées pour effectuer tous les calculs de feuille de calcul. Cependant, ce processus peut être très long et sujet aux erreurs. En fait, il s'agit d'un interpréteur auto-construit dans le programme de feuille de calcul, ce qui réduira la vitesse de fonctionnement. Ce projet utilise un autre schéma. Toutes les formules de feuille de calcul peuvent en fait être des fonctions Python. Les paramètres de la fonction sont les coordonnées x et y de la cellule évaluée et la feuille de calcul elle-même. Utilisez les opérateurs arithmétiques Python standard pour calculer le résultat et cell_value
extraire les valeurs nécessaires de la feuille de calcul. . Vous pouvez définir une safe_apply
fonction nommée , try
utiliser les paramètres correspondants dans le bloc pour terminer l'appel de la formule et renvoyer le résultat du calcul selon que la formule est calculée avec succès ou renvoie None
:
def safe_apply(function, x, y, spreadsheet):
try:
return function(x, y, spreadsheet)
except TypeError:
return None
Les deux changements ci-dessus sont suffisants pour ajouter None
le concept de null ( ) à la sémantique de la feuille de calcul . Si vous n'utilisez pas le mécanisme d'exception pour développer les fonctions ci-dessus, ce sera un exercice très instructif (l'implication est que vous pouvez expérimenter une quantité de travail considérable).
14.2.9 Occasions applicables pour les exceptions
Utiliser des exceptions pour gérer presque toutes les erreurs est une solution naturelle. Souvent, la partie de gestion des erreurs sera ajoutée lorsque le reste du programme sera pratiquement terminé. Malheureusement, c'est le cas, mais le mécanisme d'exception est très efficace pour écrire ce type de code de gestion post-erreur d'une manière facile à comprendre. Il est préférable d'ajouter plus de code de gestion d'erreur après coup.
S'il y a des branches de calcul dans le programme qui ne sont manifestement pas viables, alors il peut y avoir un grand nombre de procédures de traitement à ignorer, alors le mécanisme d'exception sera également très utile. C'est le cas de l'exemple de feuille de calcul. D'autres scénarios d'application incluent des algorithmes de branchement et de liaison et des algorithmes d'analyse.
Test rapide: des exceptions Python anormales entraîneront-elles l'abandon du programme?
Supposons que vous souhaitiez accéder à l'objet dictionnaire
x
, si la clé n'existe pas, c'est-à-dire qu'elle est déclenchéeKeyError
, puis retournezNone
. Comment écrire du code pour atteindre cet objectif?
Question pratique: Exception d' écrire du code pour créer une personnalisation
ValueTooLarge
et de lax
lever lorsque la variable est supérieure à 1000.
Cet article est extrait de "Python Quick Start (3e édition)"
Il s'agit d'un livre de démarrage rapide Python, écrit basé sur Python 3.6. Le livre est divisé en 4 parties. La première partie explique les bases de Python et donne une brève introduction à Python; la deuxième partie présente les points clés de la programmation Python, impliquant des listes, des tuples, des ensembles, des chaînes, des dictionnaires, le contrôle de flux, des fonctions et des modules Et la portée, le système de fichiers, les exceptions, etc.; la troisième partie explique les fonctionnalités avancées de Python, impliquant des classes et des expressions régulières orientées objet, des types de données, c'est-à-dire des objets, des packages, des bibliothèques Python, etc.; la quatrième partie se concentre sur le traitement des données, impliquant Le traitement des fichiers de données, les données du réseau, le stockage de données et l'exploration des données, et enfin les cas associés sont donnés.
Ce livre a une structure de cadre claire, une mise en page raisonnable du contenu, une explication étape par étape et un grand nombre d'exemples et d'exercices, afin que les lecteurs puissent rapidement apprendre et maîtriser Python.