Premiers pas avec Python: mécanisme d'exception intégré de Python

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 raiseobjets générés automatiquement par les fonctions Python . Une fois que l'objet d'exception est généré, l' raiseinstruction 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 raisel'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:

 
  1. BaseException
  2. SystemExit
  3. KeyboardInterrupt
  4. GeneratorExit
  5. Exception
  6. StopIteration
  7. ArithmeticError
  8. FloatingPointError
  9. OverflowError
  10. ZeroDivisionError
  11. AssertionError
  12. AttributeError
  13. BufferError
  14. EOFError
  15. ImportError
  16. ModuleNotFoundError
  17. LookupError
  18. IndexError
  19. KeyError
  20. MemoryError
  21. NameError
  22. UnboundLocalError
  23. OSError
  24. BlockingIOError
  25. ChildProcessError
  26. ConnectionError
  27. BrokenPipeError
  28. ConnectionAbortedError
  29. ConnectionRefusedError
  30. ConnectionResetError
  31. FileExistsError
  32. FileNotFoundError
  33. InterruptedError
  34. IsADirectoryError
  35. NotADirectoryError
  36. PermissionError
  37. ProcessLookupError
  38. TimeoutError
  39. ReferenceError
  40. RuntimeError
  41. NotImplementedError
  42. RecursionError
  43. SyntaxError
  44. IndentationError
  45. TabError
  46. SystemError
  47. TypeError
  48. ValueError
  49. UnicodeError
  50. UnicodeDecodeError
  51. UnicodeEncodeError
  52. UnicodeTranslateError
  53. Warning
  54. DeprecationWarning
  55. PendingDeprecationWarning
  56. RuntimeWarning
  57. SyntaxWarning
  58. UserWarning
  59. FutureWarning
  60. ImportWarning
  61. UnicodeWarning
  62. BytesWarningException
  63. 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, IndexErroraussi des LookupErrorclasses et des Exceptionclasses (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 Exceptionsous-classes et non des BaseExceptionsous-classes. La raison en est la suivante.

 
  1. try:
  2. # 执行一些异常操作
  3. except Exception:
  4. # 处理异常

{: -} Dans le code ci-dessus, vous pouvez toujours utiliser Ctrl + C pour suspendre tryl'exécution du bloc d'instructions sans provoquer de code de gestion des exceptions. Parce que l' KeyboardInterruptexception n'est pas Exceptionune 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:

 
  1. >>> alist = [1, 2, 3]
  2. >>> element = alist[7]
  3. Traceback (innermost last):
  4. File "<stdin>", line 1, in ?
  5. 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 IndexErrorune 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 raiseinstructions pour déclencher explicitement des exceptions. raiseLa forme la plus élémentaire de la déclaration est la suivante:

 
  1. 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 raisesera généré la pile de fonctions Python, qui est raisela 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:

 
  1. >>> raise IndexError("Just kidding")
  2. Traceback (innermost last):
  3. File "<stdin>", line 1, in ?
  4. IndexError: Just kidding

raiseLes 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 tryet exceptparfois par elsemot-clé:

 
  1. try:
  2. body
  3. except exception_type1 as var1:
  4. exception_code1
  5. except exception_type2 as var2:
  6. exception_code2
  7. .
  8. .
  9. .
  10. except:
  11. default_exception_code
  12. else:
  13. else_body
  14. finally:
  15. finally_body

La première partie de l' tryinstruction est exécutée body. Si l'exécution réussit, c'est-à-dire que l' tryinstruction n'a pas détecté d'exception levée, puis exécutez la else_bodypartie et l' tryinstruction est exécutée. Puisqu'il y a une finallyinstruction ici , une partie sera exécutée ensuite finally_body. Si une exception est trylevée, chaque exceptclause sera recherchée à son tour pour trouver la clause qui correspond au type d'exception associé avec l'exception levée. Si une exceptclause 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 exceptle 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 varet la valeur exceptsera varaffectée avant d' exécuter le code de gestion des exceptions de l' instruction exc. varCe 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 exceptclause correspondante n'est trouvée , l' tryinstruction 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 trygère.

tryLa dernière exceptclause 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 exceptcouvertes par des clauses, ce qui peut rendre certains comportements du programme difficiles à comprendre.

tryLes elseclauses 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' tryinstruction est exécutée.bodyelse

tryDéclaration finallyclause est également facultative, dans try, except, les elsepièces sont exécutées après la mise en œuvre. Si tryune exception est déclenchée dans le bloc et n'a été excepttraitée par aucun bloc, finallyl'exception sera à nouveau déclenchée après l'exécution du bloc. Étant donné que le finallybloc 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:

 
  1. class MyError(Exception):
  2. pass

{: -} Le ​​code ci-dessus crée une classe qui héritera de Exceptiontout 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:

 
  1. >>> raise MyError("Some information about what went wrong")
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. __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:

 
  1. try:
  2. raise MyError("Some information about what went wrong")
  3. except MyError as error:
  4. print("Situation:", error)

Le résultat de l'opération sera le suivant:

 
  1. 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 errorles argsattributs de la variable :

 
  1. try:
  2. raise MyError("Some information", "my_filename", 3)
  3. except MyError as error:
  4. print("Situation: {0} with file {1}\n error code: {2}".format(
  5. error.args[0],
  6. error.args[1], error.args[2]))

Le résultat de l'opération sera le suivant:

 
  1. Situation: Some information with file my_filename
  2. error code: 3

Le type d'exception est une classe Python standard et hérite de la Exceptionclasse, 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 Exceptionsous - 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 WeatherLibraryExceptionclasse distincte nommée , puis définir toutes les différentes exceptions de la bibliothèque en tant que WeatherLibraryExceptionsous-classes.

Mesure de vitesse Sujet: Hypothèses MyErrorde Exceptionclasse «exception» héritées de la classe, je demande except Exception as e, et except MyError as equelle est la différence?

14.2.5 Utilisation des instructions assert pour déboguer des programmes

assertLa déclaration est raiseune forme spéciale de déclaration:

 
  1. assert expression, argument

Si expressionle résultat du règlement est Falseet que la variable système l' __debug__est également True, argumentune AssertionErrorexception 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 -Oou -OO, ou définissez la variable système PYTHONOPTIMIZEsur True, que vous pouvez __debug__définir sur False. Des paramètres facultatifs argumentpeuvent être utilisés pour placer assertles informations d'explication.

Si __debug__c'est le cas False, le générateur de code ne assertcréera pas l'instruction de code. Dans la phase de développement, vous pouvez utiliser des assertinstructions pour coopérer avec des instructions de débogage pour tester le code. assertL'instruction peut être stockée dans le code pour une utilisation future, et il n'y a pas de surcharge pendant l'utilisation normale:

 
  1. >>> x = (1, 2, 3)
  2. >>> assert len(x) > 5, "len(x) not > 5"
  3. Traceback (most recent call last):
  4. File "<stdin>", line 1, in <module>
  5. 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' assertinstruction pour provoquer une exception lorsque le nombre est 0. Tout d'abord, veuillez tester pour garantir assertl'exécution de l'instruction, puis désactivez-la via les méthodes mentionnées dans cette section assert.

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 exceptla signification de cette architecture pour savoir comment les clauses interceptent les exceptions.

Considérez le code suivant:

 
  1. try:
  2. body
  3. except LookupError as error:
  4. exception code
  5. except IndexError as error:
  6. exception code

Ici seront capturés IndexErroret LookupErrorles deux exceptions. Il se trouve que IndexErrorc'est LookupErrorune sous-classe. Si elle est bodylancée IndexError, l'erreur sera d'abord except LookupError as error:détectée par la ligne " ". En raison de l' IndexErrorhéritage LookupError, la première exceptclause sera exécutée avec succès et la deuxième exceptclause ne sera jamais utilisée car ses conditions de fonctionnement sont exceptincluses dans la première clause.

Au contraire, exceptil 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 IndexErrorque 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:

 
  1. def save_to_file(filename) :
  2. try:
  3. save_text_to_file(filename)
  4. save_formats_to_file(filename)
  5. save_prefs_to_file(filename)
  6. .
  7. .
  8. .
  9. except IOError:
  10. ...处理错误...
  11. def save_text_to_file(filename):
  12. ...调用底层函数来写入文本大小...
  13. ...调用底层函数来写入实际的文本数据...
  14. .
  15. .
  16. .

Notez que le code de gestion des erreurs est très discret save_to_fileet 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 IOErrorexceptions. La fonction intégrée de Python lèvera automatiquement IOErrorune 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 exceptvé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, exceptle 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 exceptcorps 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 DiskFullexception 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 0valeurs. Les cellules contenant toute autre chaîne non numérique peuvent être considérées comme non valides et exprimées sous forme de Nonevaleurs 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:

 
  1. def cell_value(string):
  2. try:
  3. return float(string)
  4. except ValueError:
  5. if string == "":
  6. return 0
  7. else:
  8. return None

Les capacités de gestion des exceptions de Python rendent cette fonction très simple à écrire. Dans le trybloc, la chaîne de la cellule est floatconvertie 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 floatfonction lève ValueErrorune exception. Ensuite, le code de gestion des exceptions interceptera l'exception et retournera 0ou None, selon que la chaîne de paramètre est une chaîne vide.

Parfois, il peut être nécessaire Nonede 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_valueextraire les valeurs nécessaires de la feuille de calcul. . Vous pouvez définir une safe_applyfonction nommée , tryutiliser 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:

 
  1. def safe_apply(function, x, y, spreadsheet):
  2. try:
  3. return function(x, y, spreadsheet)
  4. except TypeError:
  5. return None

Les deux changements ci-dessus sont suffisants pour ajouter Nonele 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ée KeyError, puis retournez None. Comment écrire du code pour atteindre cet objectif?

 

Question pratique: Exception d' écrire du code pour créer une personnalisation ValueTooLargeet de la xlever 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.

Je suppose que tu aimes

Origine blog.csdn.net/epubit17/article/details/108506470
conseillé
Classement