Modules et débogage Python, bases des tests

Apprends à utiliser du code existant et à rendre ton propre code fiable. Importe des modules de la bibliothèque standard de Python comme math et random, écris tes propres modules et installe des paquets depuis PyPI avec pip. Lis ensuite les traces d’appels et les messages d’erreur, trouve les bugs grâce à une démarche de débogage pas à pas et vérifie tes fonctions avec des instructions assert et tes premiers tests unitaires.

DébutantUnité 9 sur 10 de la formation Formation : Python : variables, boucles, fonctions et fichiers

Ce que tu vas apprendre

  1. Importer du code prêt à l’emploi dans un programme avec des instructions import, utiliser des modules de la bibliothèque standard comme math et random, répartir ton code dans des modules et installer des paquets tiers avec pip.
    • Importer du code dans un programme avec l’instruction import
      Utiliser correctement import, from … import et as, accéder aux noms par notation pointée et distinguer les erreurs d’importation.
    • Calculer et simuler avec math, random et d’autres modules standard
      Utiliser les principales fonctions de math et random, éviter leurs pièges courants et connaître quelques autres modules courants de la bibliothèque standard.
    • Écrire et importer tes propres modules
      Répartir le code dans tes propres fichiers .py, les importer, éviter les conflits de noms et utiliser if __name__ == "__main__": pour qu’un fichier puisse être à la fois exécuté et importé.
    • Installer et gérer des paquets avec pip
      Installer, examiner, mettre à niveau et supprimer des paquets tiers depuis PyPI, les importer sous le bon nom et résoudre les problèmes d’installation courants.
  2. Utiliser les messages d’erreur de Python pour trouver où et pourquoi un programme a échoué, et distinguer les erreurs de syntaxe, d’exécution et de logique.
    • Lire une trace d’appels de bas en haut
      Trouver le type d’exception, le message, la ligne qui a échoué et la chaîne d’appels qui y a conduit.
    • Reconnaître les erreurs courantes et leurs causes
      Relier les types d’exceptions les plus fréquents à leurs causes et corrections habituelles, et repérer les erreurs de logique qui ne produisent aucun message.
  3. Localiser la cause d’un bug grâce à une démarche pas à pas au lieu de procéder au hasard, et examiner un programme en cours d’exécution avec des appels à print et un débogueur.
    • Suivre une démarche de débogage pas à pas
      Reproduire un bug, formuler et tester une hypothèse, cerner la cause, la corriger et effectuer de nouveaux tests.
    • Examiner un programme avec des appels à print, des tableaux de suivi et un débogueur
      Observer comment les valeurs changent pendant l’exécution du code, en ajoutant des appels à print, en suivant l’exécution à la main ou en mettant le programme en pause à des points d’arrêt.
  4. Utiliser assert pour indiquer ce qui doit être vrai, écrire de petits tests automatisés pour tes fonctions, puis les exécuter et les lire avec le module standard unittest.
    • Vérifier des hypothèses avec l’instruction assert
      Écrire des instructions assert avec des messages clairs et savoir quand les assertions sont adaptées ou non.
    • Écrire tes premiers tests unitaires pour tes fonctions
      Écrire des fonctions de test avec des assertions, choisir des cas typiques, des cas aux limites et des cas extrêmes, et utiliser les tests qui échouent pour trouver et corriger les bugs.
    • Organiser et exécuter des tests avec unittest
      Écrire des tests unittest.TestCase, les exécuter et lire le rapport des tests réussis, des échecs de test et des erreurs.

Modules et débogage Python : cours

4 chapitres

1

Réutiliser des modules et installer des paquets

Le code importé permet à un petit programme d’utiliser des calculs, des simulations et des outils écrits ailleurs. Tu vas choisir une forme d’importation, utiliser des fonctions de la bibliothèque standard et organiser tes propres fonctions pour qu’un autre fichier puisse les réutiliser. L’installation soulève une question distincte : quelle installation de Python reçoit un paquet tiers ? Comprendre ce lien facilite le diagnostic d’un module manquant et permet de garder clairs les noms de chaque programme.

1.1 Importer un module ou des noms choisis

Un module contient du code Python qu’un autre programme peut réutiliser. La plupart des modules sont des fichiers .py. La bibliothèque standard est fournie avec Python ; le code tiers nécessite une installation séparée. Un paquet regroupe des modules apparentés, généralement dans un dossier.

Adapter l’appel à l’importation

Une importation crée des noms dans ton programme. La forme choisie détermine comment tu appelles le code importé.

InstructionNom crééExemple d’appel
import mathmathmath.sqrt(16)
from math import sqrtsqrtsqrt(16)
import statistics as statsstatsstats.mean([2, 4, 9])
from random import randint as rollrollroll(1, 6)

La notation pointée permet de rechercher un nom dans un module ou un objet. Dans math.sqrt(16), Python trouve sqrt dans math et l’appelle avec 16. Le résultat est 4.0. La constante math.pi ne nécessite pas de parenthèses d’appel, car c’est une valeur, pas une fonction.

Après import math, sqrt(16) seul lève NameError : le programme possède un nom pour le module, mais aucun nom distinct pour sqrt. Après from math import sqrt seul, l’erreur inverse, math.sqrt(16), lève aussi NameError parce que math n’a pas été lié. Un alias remplace le nom habituel de la liaison importée : import statistics as stats crée stats, pas les deux noms.

Effectuer le même calcul de deux façons

Un triangle rectangle a des côtés de longueurs 3 et 4. Élève d’abord les côtés au carré et additionne-les, puis prends la racine carrée.

import math

length = math.sqrt(3**2 + 4**2)
print(length)  # 5.0

L’expression dans l’appel devient 9 + 16, puis 25 ; sqrt renvoie 5.0. Avec from math import sqrt, écris plutôt length = sqrt(3**2 + 4**2). Le préfixe du module rend visible l’origine d’une fonction et évite d’introduire ses autres noms dans l’espace de noms de ton programme. La liaison math elle-même peut toutefois remplacer une variable antérieure appelée math.

Garder des noms clairs

Évite from math import *. Cette importation générique introduit les noms publics dans ton programme sans les nommer individuellement. Par exemple, e = 5 suivi de cette importation fait passer e à 2.718281828459045. Une importation qui semble sans rapport peut donc modifier un calcul ultérieur. PEP 8 recommande les importations explicites et les place en haut du fichier, à raison d’un module par ligne : bibliothèque standard d’abord, paquets tiers ensuite, tes propres modules en dernier.

Python exécute le code de premier niveau d’un module lors de sa première importation pendant l’exécution d’un programme. Les importations suivantes réutilisent le module chargé ; elles ne le relancent pas.

Utiliser l’erreur pour choisir la correction
ErreurCe qu’il faut examiner
ModuleNotFoundError avec import mathhL’orthographe et l’installation du module
ImportError avec from math import square_rootLe nom demandé au module
AttributeError avec math.sqroot(16)Le nom après le point

Dans la console interactive, exécute import math, puis dir(math) pour lister ses noms. Exécute help(math.sqrt) pour lire la documentation d’une fonction. La référence officielle de la bibliothèque Python explique ses arguments et son résultat.

Points clés

  • import module crée une liaison pour le module ; accède à son contenu avec la notation pointée.
  • from module import name crée la liaison choisie ; as permet de choisir un alias.
  • Les importations explicites rendent l’origine des noms claire et réduisent les remplacements accidentels.
  • Les erreurs d’importation distinguent un module introuvable, un nom importé indisponible et un attribut manquant.
  • dir() liste les noms ; help() explique comment en utiliser un.

1.2 Choisir les fonctions de math et random

La bibliothèque standard fournit des outils testés pour les calculs et les simulations. Le choix d’une fonction commence par le résultat recherché : un nombre entier, une mesure arrondie, un élément aléatoire ou une liste réorganisée.

L’arrondi a plusieurs sens

Après import math, math.sqrt(16) renvoie le flottant 4.0. math.pi et math.e fournissent les constantes 3.141592653589793 et 2.718281828459045. math.factorial(5) multiplie les nombres entiers de 1 à 5 et renvoie 120.

ExpressionRésultatSignification
math.floor(7.9)7Plus grand entier inférieur ou égal à la valeur
math.ceil(2.1)3Plus petit entier supérieur ou égal à la valeur
math.floor(-2.5)-3L’arrondi inférieur va vers l’infini négatif
int(-3.5)-3La conversion tronque vers zéro
round(2.5)2Une valeur exactement à mi-chemin est arrondie au pair
round(3.5)4L’entier pair voisin est 4

Pour 23 mètres carrés de mur et 10 mètres carrés par pot de peinture, la division donne 2.3 pots. Pour acheter des pots entiers, il faut utiliser math.ceil(23 / 10), qui renvoie 3. round(2.3) donne 2 et laisse trop peu de peinture.

La fonction native round() ne nécessite aucune importation. Pour un cercle de rayon 2, round(math.pi * 2 ** 2, 2) donne 12.57. L’arrondi modifie la précision d’un nombre ; c’est une opération différente de l’achat d’un nombre suffisant de pots entiers.

Vérifier les domaines de définition et les comparaisons de flottants

math.sqrt(-1) lève ValueError, car cette entrée n’a pas de racine carrée réelle. Les flottants calculés demandent aussi de l’attention : à cause du stockage binaire, 0.1 + 0.2 == 0.3 vaut False. math.isclose(0.1 + 0.2, 0.3) vaut True ; utilise cette fonction pour comparer approximativement des flottants calculés.

Choisir l’opération aléatoire

Le module random utilise un algorithme pour produire des résultats pseudo-aléatoires.

AppelRésultat
random.randint(1, 6)Un entier de 1 à 6, bornes comprises
random.randrange(1, 6)Un entier de 1 à 5
random.random()Un flottant supérieur ou égal à 0,0 et strictement inférieur à 1,0
random.uniform(a, b)Un flottant entre les bornes fournies
random.choice(items)Un élément
random.sample(items, k)Des éléments à k positions, sans remise
random.shuffle(items)Réorganise la liste existante ; renvoie None

Garde random.shuffle(cards) sur sa propre ligne. Réaffecter son résultat à cards fait perdre la liaison à la liste en la remplaçant par None. Tirer des positions est aussi différent d’exiger des valeurs distinctes : random.sample([1, 1], 2) renvoie [1, 1].

Exécuter une simulation reproductible
import random

sevens = 0
for _ in range(1000):
    if random.randint(1, 6) + random.randint(1, 6) == 7:
        sevens += 1
print(sevens)

Six des 36 couples équiprobables ont une somme de 7 : le nombre obtenu est donc généralement proche de 167, mais il change d’une exécution à l’autre. Pour reproduire une séquence lors du débogage, appelle random.seed(42) avant de générer les valeurs, avec la même version de Python et la même séquence d’appels. Pour les mots de passe ou les jetons de sécurité, utilise secrets.

Trouver d’autres outils courants

statistics.mean([2, 4, 9]) renvoie 5 ; statistics.median([2, 4, 9]) renvoie 4. datetime.date.today() donne la date du jour. Après import sys, sys.argv contient le nom du script suivi de ses arguments : l’exécution de python greet.py Ada fournit ['greet.py', 'Ada'].

Points clés

  • floor, ceil, int et round répondent à différentes questions d’arrondi.
  • Utilise math.isclose pour comparer des flottants calculés.
  • randint inclut les deux bornes ; randrange exclut sa borne de fin.
  • sample choisit des positions sans remise : des valeurs identiques dans l’entrée peuvent donc être répétées.
  • shuffle modifie une liste en place et renvoie None.
  • Une graine fixe aide à reproduire un comportement aléatoire ; les jetons de sécurité nécessitent secrets.

1.3 Rendre un fichier réutilisable sans lancer son programme

Une fonction devient plus facile à réutiliser lorsqu’elle se trouve dans un module consacré à une tâche précise. Un autre programme peut importer cette fonction et un test peut la vérifier sans demander à une personne d’exécuter toute l’application.

Séparer la fonction de son appelant

Enregistre ce code sous le nom geometry.py :

"""Calculations for simple shapes."""
import math

def circle_area(radius):
    """Return the area of a circle with the given radius."""
    return math.pi * radius ** 2

Dans le même dossier, enregistre cet appelant sous le nom main.py :

import geometry

print(geometry.circle_area(2))

Exécute python main.py. Python trouve geometry, crée sa fonction, puis l’appelant exécute cette fonction. Le résultat affiché est 12.566370614359172. Importe le module sans la terminaison .py. Un nom de module valide utilise des lettres, des chiffres et des tirets bas, avec un premier caractère valide ; my_tools.py fonctionne avec import my_tools, tandis que import my-tools est une syntaxe invalide.

Les chaînes au début du module et de la fonction sont des docstrings. Elles décrivent le rôle du code et apparaissent dans help(geometry) et help(geometry.circle_area).

Comprendre ce que l’importation exécute

Lors de la première importation, Python exécute dans l’ordre les instructions de premier niveau du module. Une instruction def crée une fonction ; elle n’exécute pas son corps. En revanche, un print(circle_area(2)) non protégé à la fin de geometry.py produirait un affichage pendant l’importation.

Cet effet de bord compte lorsqu’un module contient des invites de saisie ou une boucle de programme. Un test qui veut seulement utiliser circle_area ne devrait pas avoir à lancer le programme et à répondre à ses invites.

Protéger le lancement et garder la fonction accessible

Ajoute ceci sous la fonction réutilisable dans geometry.py :

def main():
    print(circle_area(2))

if __name__ == "__main__":
    main()

Python définit __name__ pour chaque module. Une exécution directe, python geometry.py, lui donne la valeur "__main__", ce qui rend la condition vraie et appelle main(). L’importation de geometry lui donne la valeur "geometry" : Python ignore donc l’appel. Les définitions placées au-dessus de la garde restent disponibles dans les deux cas.

Ne place pas circle_area elle-même dans la garde. Un programme qui importe le module a besoin de cette définition même lorsque la condition de lancement est fausse. La garde contrôle le moment où l’application démarre ; elle n’empêche pas Python de charger le module.

Savoir où Python cherche

Python vérifie les modules intégrés comme sys, puis parcourt dans l’ordre les dossiers de sys.path. Normalement, le dossier du script exécuté vient en premier dans ce chemin, suivi des dossiers de la bibliothèque standard et des paquets installés. Garder tes propres fichiers à côté du script exécuté est une organisation simple pour un projet de débutant. Une importation ordinaire ne peut pas trouver un module situé hors du chemin de recherche.

Cet ordre peut aussi masquer un module de bibliothèque. Si tu enregistres ton programme sous le nom random.py, son instruction import random peut charger ton fichier à la place du module de bibliothèque. Un appel ultérieur à random.randint(1, 6) lève alors AttributeError. Renomme le fichier, par exemple en dice.py ; Python 3.13 et les versions ultérieures peuvent inclure une indication de renommage dans l’erreur.

Un module chargé est réutilisé au cours d’une même exécution. Dans une console interactive, modifier le fichier et l’importer à nouveau conserve la version chargée. Redémarre la console avant de tester tes modifications.

Points clés

  • Importe ton propre fichier .py en utilisant son nom de module sans l’extension.
  • Une importation exécute les instructions de premier niveau, tandis que les corps de fonctions attendent d’être appelés.
  • Garde les définitions réutilisables hors de la garde __main__ et le lancement du programme à l’intérieur.
  • Un fichier local peut masquer un module de bibliothèque qui porte le même nom.
  • Redémarre une console interactive pour tester à nouveau un module modifié.

1.4 Installer des paquets pour le Python que tu exécutes

Les paquets tiers ajoutent du code qui n’est pas fourni avec Python. PyPI, le Python Package Index accessible sur https://pypi.org, héberge ces projets. pip les télécharge et les installe pour une installation particulière de Python.

Utiliser le terminal, puis Python

Une commande de terminal et une instruction Python ne se saisissent pas au même endroit. L’invite >>> signifie que tu es dans la console interactive Python. Y saisir pip install requests donne SyntaxError ; Python ne peut pas l’interpréter comme une instruction.

Dans ton terminal, exécute :

python -m pip install cowsay

Puis place ceci dans un programme Python :

import cowsay

cowsay.cow("Hello, Ada")

Le programme affiche une vache dessinée avec des caractères à côté d’une bulle contenant le message. L’installation rend le paquet disponible ; l’importation crée la liaison correspondante dans le programme.

Associer pip à ton interpréteur

La forme -m pip demande au Python indiqué d’exécuter son propre pip. Utilise la commande qui lance tes programmes : souvent python3 sur macOS ou Linux, ou py sur Windows.

python3 -m pip install cowsay
python3 game.py

Les deux lignes utilisent la même commande Python. Si une installation réussit mais qu’un script lève encore ModuleNotFoundError, compare le Python utilisé pour l’installation avec celui utilisé pour exécuter le script. Un éditeur peut avoir sélectionné un interpréteur différent de celui de ton terminal. Utilise le pip de l’interpréteur sélectionné avant de modifier l’importation.

Examiner et entretenir une installation
Commande de terminalRôle
python -m pip listLister les paquets installés et leurs versions
python -m pip show requestsAfficher les détails, dont l’emplacement d’installation
python -m pip install --upgrade requestsMettre à jour vers la dernière version disponible
python -m pip install "requests==2.32.3"Choisir cette version précise
python -m pip uninstall requestsSupprimer le paquet

Une version précise est utile lorsque tu as besoin du comportement propre à cette version. show aide à vérifier quel emplacement pip a réellement modifié.

Vérifier le nom dans la documentation

Le nom de distribution saisi pour pip peut différer du nom d’importation. Installe beautifulsoup4, puis utilise import bs4 ; installe Pillow, puis utilise import PIL. Installer à plusieurs reprises un nom d’importation n’est pas une correction utile lorsque la documentation indique une autre distribution.

La bibliothèque standard de Python, y compris math, random et unittest, est déjà fournie avec Python. Ces modules ne nécessitent pas d’installation avec pip.

Respecter une installation gérée

Certains systèmes d’exploitation et gestionnaires de paquets protègent leur Python avec une erreur externally-managed-environment. Cela signifie qu’une installation directe est bloquée pour préserver la cohérence de l’installation gérée. Utilise un environnement virtuel, avec un Python et un dossier de paquets distincts pour le projet. Ne force pas l’installation avec sudo pip install.

Tout le monde peut publier sur PyPI. Avant l’installation, vérifie l’orthographe exacte et lis la page et la documentation du projet. Des noms ressemblants peuvent être des tentatives de typosquatting. Privilégie les paquets établis et maintenus, et installe ceux dont ton programme a réellement besoin.

Points clés

  • Exécute les commandes pip dans un terminal et les importations dans le code Python.
  • Utilise python -m pip avec la même commande d’interpréteur que celle qui exécute le programme.
  • Vérifie le nom d’importation dans la documentation ; il peut différer du nom d’installation.
  • Utilise pip pour examiner, mettre à jour ou supprimer un paquet, ou pour choisir sa version.
  • Un Python géré peut nécessiter un environnement virtuel pour le projet.
  • Vérifie l’orthographe du nom et la documentation du paquet avant d’installer du code tiers.
2

Lire les erreurs et les traces d’appels

Les messages d’erreur de Python indiquent à la fois l’opération qui a échoué et les appels qui y ont conduit. Lire ces indices dans l’ordre aide à trouver un point de départ utile au lieu de modifier la première ligne que tu reconnais. Tu vas remonter une trace d’appels jusqu’à l’entrée en cause, distinguer les types d’exceptions courants et reconnaître le cas plus discret où un programme s’exécute normalement mais produit un résultat incorrect. Le comportement attendu te donne un élément concret à vérifier.

2.1 Remonter une trace d’appels jusqu’à l’entrée incorrecte

Une trace d’appels indique quels appels étaient actifs lorsqu’une exception non gérée a arrêté le programme. Elle fournit à la fois un point de départ pour la lecture et un chemin pour remonter jusqu’à la valeur qui a provoqué l’échec.

Commencer par la dernière ligne

Considère ce programme complet dans scores.py :

def average(values):
    return sum(values) / len(values)

def report(scores):
    avg = average(scores)
    print(f"Average: {avg:.1f}")

report([])

La dernière ligne de son rapport d’erreur est ZeroDivisionError: division by zero. Elle nomme le type d’exception et décrit l’opération qui a échoué. Commence par là, puis remonte jusqu’à l’emplacement du code juste au-dessus.

Voici une trace d’appels simplifiée, sans les marques d’expression :

Traceback (most recent call last):
  File "scores.py", line 8, in <module>
    report([])
  File "scores.py", line 5, in report
    avg = average(scores)
  File "scores.py", line 2, in average
    return sum(values) / len(values)
ZeroDivisionError: division by zero
Lire chaque cadre comme un appel actif

Un cadre d’exécution indique le fichier, le numéro de ligne et la fonction, suivis du code concerné. in <module> désigne le code de premier niveau. L’appel le plus ancien est en haut ; le plus récent est en bas. Lire en partant du bas inverse cet ordre et permet de se demander ce qui a échoué avant de chercher comment l’exécution en est arrivée là.

  1. La ligne 2 divise par len(values). Pour que ce diviseur soit nul, values doit être vide.
  2. La ligne 5 appelle average(scores) : examine donc les scores transmis par report.
  3. La ligne 8 fournit [], la liste vide. Cela explique comment le diviseur nul est arrivé dans le calcul.

La ligne qui échoue et la cause sont liées, mais peuvent se trouver à des endroits différents. Remplacer la division sans décider de ce que doit signifier une liste vide masquerait une question de conception. L’appelant doit soit éviter une liste vide, soit définir le comportement de la fonction pour une entrée vide.

Utiliser les marques sans dépendre de leur forme exacte

Python 3.11 et les versions ultérieures peuvent ajouter les caractères ^ et ~ pour montrer la partie d’une expression qui a échoué. Ils sont utiles lorsqu’une ligne contient plusieurs opérations. Les marques exactes varient selon la version, mais les emplacements des appels et le message d’exception donnent toujours l’ordre de lecture.

Une trace d’appels peut contenir des cadres de la bibliothèque standard ou d’un paquet installé. Trouve le cadre le plus bas dans ton propre code et examine les arguments que tu y as fournis. Un cadre de bibliothèque indique un emplacement ; il ne prouve pas que la bibliothèque contient le bug.

Reconnaître un rapport d’erreur de syntaxe

Une erreur de syntaxe dans le script lancé empêche ce script de s’exécuter. Python indique un fichier, une ligne, une marque et un message sans l’en-tête habituel de trace d’appels. Par exemple, il manque les deux-points à if True ; total = sum([1, 2, 3] laisse une parenthèse ouverte.

L’emplacement marqué est celui où Python a constaté qu’il ne pouvait pas analyser le code. Lorsque cette ligne semble valide, vérifie si un guillemet ou une parenthèse n’a pas été laissé ouvert à la ligne précédente. Il n’y a pas de chaîne d’appels à l’exécution à suivre lorsque le script lancé ne s’est pas exécuté.

Une exécution ordinaire s’arrête à sa première exception non gérée. Corrige ce problème et relance le programme pour faire apparaître les éventuels problèmes ultérieurs.

Points clés

  • Lis d’abord le type d’exception et le message, puis le cadre qui a échoué et ses appelants.
  • Les cadres vont de l’appel actif le plus ancien en haut au plus récent en bas.
  • Remonte le parcours de la valeur incorrecte ; sa source peut précéder l’arrêt.
  • Une erreur de syntaxe dans le script lancé est signalée avant son exécution.

2.2 Distinguer un nom, un type, une valeur et un résultat incorrects

Le nom d’une erreur réduit le champ de recherche et son message apporte des précisions sur les valeurs concernées. Un programme peut aussi être incorrect sans lever d’exception : vérifier sa sortie par rapport au résultat attendu reste donc nécessaire pour trouver les erreurs.

Distinguer trois types de problèmes
TypeCe qui se passeExemple
Erreur de syntaxePython ne peut pas analyser le codeDeux-points manquants après if
Erreur d’exécutionL’exécution atteint une opération invalideDivision par zéro
Erreur de logiqueL’exécution se termine avec un comportement incorrectUne boucle ignore un prix

IndentationError est un type de SyntaxError. Le corps d’une fonction doit être indenté ; l’absence d’un bloc indenté arrête le code avant son exécution. Vérifie aussi les guillemets ou parenthèses non fermés et les mots-clés mal orthographiés.

Examiner les noms et les types

Une NameError signifie que le programme ne connaît pas un nom à cet endroit. Dans prnt("hi"), la fonction native voulue est print. Un nom peut aussi être utilisé avant son affectation, ou une importation peut manquer.

Une TypeError signifie qu’une opération a reçu un type inadapté ou qu’un appel a reçu un nombre incorrect d’arguments. "Age: " + 30 mélange une chaîne et un entier. Écris "Age: " + str(30) ou f"Age: {30}". Si area attend w et h, area(3) provoque aussi une TypeError, cette fois à cause d’un argument manquant.

Le message distingue ces causes. Dans can only concatenate str (not "int") to str, Python nomme les types concernés. Après age = input("Age: "), age est du texte. age + 1 échoue ; pour une saisie entière, int(age) + 1 effectue le calcul.

Une ValueError signifie que le type de l’entrée est accepté, mais que sa valeur ne convient pas. int("12.5") reçoit une chaîne, qui est un type d’entrée accepté, mais le texte ne représente pas un nombre entier sous la forme attendue. math.sqrt(-1) est un autre exemple de valeur inadaptée pour un calcul dans les nombres réels.

Vérifier les positions, les clés et les attributs
ExceptionExempleCause
IndexError[4, 6, 10][3]Le dernier indice valide est 2
KeyError{"apples": 3}["pears"]Le dictionnaire ne contient pas "pears"
ZeroDivisionError10 / 0Le diviseur est zéro
AttributeErrormath.sqroot(16)Le module ne contient pas sqroot
ModuleNotFoundErrorimport mathhAucun module n’est trouvé sous ce nom
ImportErrorfrom math import square_rootLe module ne contient pas ce nom importé

Les divisions par zéro échouent aussi avec // et %. L’accès à une position absente d’une liste diffère de l’accès à une clé absente d’un dictionnaire, même si les deux consistent à demander quelque chose qui manque.

Détecter un résultat qui semble plausible
def total_price(prices):
    total = 0
    for i in range(1, len(prices)):
        total += prices[i]
    return total

Pour [4, 6, 10], cette fonction renvoie 16 au lieu de 20. Il n’y a aucune exception : les indices 1 et 2 existent, donc chaque opération est autorisée. La boucle commence trop tard et ignore l’indice 0. L’erreur devient visible lorsque tu compares la sortie au total voulu.

Pour une exception inconnue, recherche son type et le message général dans la documentation officielle de Python. Retire tes propres chemins et valeurs d’entrée de la recherche ; ils expliquent rarement la règle générale.

Points clés

  • Les erreurs de syntaxe empêchent l’analyse du code ; les erreurs d’exécution surviennent pendant l’exécution ; les erreurs de logique produisent un comportement incorrect.
  • NameError concerne une liaison ; TypeError concerne un type ou les arguments d’un appel.
  • ValueError concerne une valeur inadaptée fournie dans un type accepté.
  • IndexError, KeyError et AttributeError désignent différents types d’accès.
  • Comparer la sortie à un résultat attendu peut révéler une erreur de logique sans trace d’appels.
3

Trouver la cause d’un bug

Un résultat incorrect est plus facile à examiner lorsque tu peux le reproduire et préciser en quoi il diffère du résultat attendu. Tu vas transformer cette observation en une hypothèse vérifiable, réduire la recherche à un petit morceau de code et examiner les valeurs qui comptent. Les affichages, les tableaux de suivi et les commandes d’un débogueur offrent différents moyens d’observer l’exécution. Après une correction ciblée, vérifier les cas qui fonctionnaient auparavant aide à révéler les comportements touchés par la modification.

3.1 Tester une cause avant de modifier le code

Un bug est une différence entre le comportement prévu et le comportement obtenu. Le débogage permet d’en trouver la cause et de la corriger. Une séance de débogage utile transforme une observation en une explication vérifiable, puis modifie le code à partir des éléments obtenus.

Reproduire l’échec

Note une entrée précise et le résultat qu’elle produit. Pour la fonction de calcul des prix qui commence sa boucle à l’indice 1, utilise [4, 6, 10]. Le total attendu est 20 ; le total obtenu est 16. Ces valeurs concrètes te permettent de vérifier que chaque étape de la recherche concerne toujours le même bug.

La différence est 4, et le résultat obtenu est égal à 6 + 10. Une hypothèse précise est que le premier prix est ignoré. Cette hypothèse prédit un fait que tu peux examiner : la boucle ne passera jamais par l’indice 0.

Suivre six étapes
  1. Reproduire : trouve une entrée qui montre le bug de façon fiable.
  2. Indiquer les résultats attendu et obtenu : calcule le résultat attendu indépendamment.
  3. Formuler une hypothèse : indique une cause possible et le comportement qu’elle prédit.
  4. La tester : examine les valeurs avec des affichages, un tableau de suivi ou un débogueur.
  5. Corriger la cause : effectue une modification ciblée.
  6. Tester à nouveau : exécute le programme avec l’entrée qui échouait et les cas qui fonctionnaient auparavant.

Affiche l’indice dans la boucle. Pour cette entrée, les seuls indices sont 1 et 2, ce qui confirme la prédiction. Faire commencer range à 0 corrige le problème de l’élément ignoré. Parcourir directement les prix évite d’avoir à gérer un indice :

def total_price(prices):
    total = 0
    for price in prices:
        total += price
    return total

La fonction corrigée renvoie 20 pour [4, 6, 10], 5 pour [5] et 0 pour []. Le cas à un élément est utile, car la boucle erronée renvoyait auparavant 0 pour ce cas.

Ajouter 4 à chaque réponse corrigerait le total observé, mais laisserait la cause en place. Pour [5], ce correctif renverrait 4 ; le montant manquant dépend de l’entrée. Vérifie si une correction proposée explique tous les éléments observés avant de la conserver.

Réduire une recherche plus vaste

La méthode diviser pour régner consiste à vérifier les valeurs qui alimentent le résultat incorrect à un point intermédiaire de l’exécution. Si une valeur nécessaire est déjà incorrecte, examine le code antérieur qui l’a produite. Si les valeurs nécessaires sont encore correctes, suis leur traitement ultérieur. Recommence dans la partie restante.

Tu peux aussi appeler une fonction isolément ou retirer temporairement le code sans rapport. Un exemple minimal reproductible conserve le code le plus court et la plus petite entrée qui échouent encore. Pour un problème observé d’abord dans des centaines d’enregistrements, trouver un ou deux enregistrements qui le déclenchent facilite chaque vérification.

Vérifier la nature réelle des données

Un 5 affiché peut être la chaîne "5". "5" + "3" produit "53", tandis que l’addition numérique donne 8. Examine type(value) pour vérifier le type. Utilise repr(value) pour révéler les espaces et les caractères de saut de ligne qu’un affichage ordinaire peut masquer, comme dans ' Ada'.

Explique le code à voix haute, ligne par ligne, en précisant notamment ce que chaque boucle parcourt réellement et ce que chaque fonction renvoie. C’est le débogage du canard en plastique : expliquer une étape révèle souvent l’écart entre l’opération voulue et celle qui est écrite.

Corrige une cause à la fois pour pouvoir relier le résultat à la modification. Teste à nouveau les cas qui fonctionnaient auparavant ainsi que celui qui échouait.

Points clés

  • Reproduis le bug et note les résultats attendu et obtenu avant toute modification.
  • Une hypothèse utile prédit un fait que tu peux examiner.
  • Corrige la cause par une modification, puis teste à nouveau les cas qui échouaient et ceux qui fonctionnaient auparavant.
  • Utilise un exemple minimal ou des valeurs intermédiaires pour réduire la zone de recherche.
  • Vérifie les types et les caractères cachés lorsque les valeurs peuvent induire en erreur.

3.2 Observer les changements de valeurs avec des affichages et un débogueur

La réponse finale d’un programme masque le chemin qui l’a produite. Des affichages temporaires, un tableau de suivi et un débogueur permettent de voir ce chemin et de vérifier une hypothèse précise sur l’endroit où il pose problème.

Afficher une valeur à un moment connu

Identifie les valeurs affichées pour le diagnostic afin que le sens de chaque nombre soit clair. Python 3.8 et les versions ultérieures prennent en charge cette forme de f-string :

print(f"{i=} {total=}")

Pour la boucle de calcul des prix erronée, place-la juste avant total += prices[i]. Avec les prix [4, 6, 10], elle affiche :

i=1 total=0
i=2 total=6

Ce sont les totaux avant chaque addition. Après le premier affichage, la boucle ajoute 6 ; après le second, elle ajoute 10. Un affichage après l’addition montrerait des totaux différents. Détermine quel moment répond à ta question avant d’interpréter la sortie.

Suivre le même code à la main

Un tableau de suivi consigne les variables étape par étape. Pour cette boucle :

Indice iPrix ajoutéTotal avantTotal après
1606
210616

Il n’y a aucune itération pour l’indice 0. Suis les valeurs réelles de début et de fin écrites dans le code, même si tu sais déjà ce que la boucle devrait faire. Un tableau aide à distinguer ce que tu attends de ce qui se passe.

Mettre en pause à un point d’arrêt

Un débogueur met un programme en cours d’exécution en pause pour te permettre d’examiner son état courant. Un point d’arrêt marque un endroit où faire une pause. Dans des éditeurs comme Thonny et VS Code, clique à côté d’un numéro de ligne et lance le mode débogage ; dans IDLE, fais un clic droit sur la ligne et choisis Set Breakpoint.

Une fois le programme en pause, choisis une commande de progression selon la question étudiée :

CommandeEffet
Pas à pas principalExécuter la ligne courante, y compris une fonction appelée
Pas à pas détailléEntrer dans une fonction appelée sur cette ligne
Sortie de fonctionTerminer cette fonction et mettre en pause après son retour
ContinuerExécuter jusqu’à un autre point d’arrêt ou à la fin du programme

Si l’appelant transmet des arguments corrects mais reçoit une réponse incorrecte, entre dans la fonction avec le pas à pas détaillé. Si tu as seulement besoin de voir le résultat renvoyé, utilise le pas à pas principal sur son appel. Examine les valeurs avant et après la ligne qui pourrait créer l’erreur.

Utiliser le débogueur textuel de Python

Insère breakpoint() juste avant le code que tu veux examiner. Avec la configuration par défaut du débogueur, l’exécution du programme lance pdb à cet endroit. Saisis ces commandes à son invite (Pdb) :

  • p total affiche total.
  • n exécute la ligne suivante en pas à pas principal.
  • s entre dans un appel de fonction.
  • c poursuit l’exécution.
  • q quitte la séance de débogage.

Ce sont des commandes du débogueur, pas des lignes à copier dans ton programme.

Distinguer l’affichage des résultats renvoyés

Une fonction peut afficher le bon nombre tout en renvoyant None parce qu’il lui manque return total. Examine la valeur reçue par l’appelant lorsque l’échec se produit après l’appel de fonction. Voir une sortie correcte dans la fonction ne prouve pas que l’appelant a reçu ce nombre.

Utilise les affichages pour obtenir rapidement des indices sur les itérations d’une boucle et le débogueur pour examiner un moment précis. Après avoir corrigé le bug, supprime les affichages temporaires et les appels à breakpoint() pour que le programme terminé s’exécute normalement.

Points clés

  • Identifie les valeurs affichées pour le débogage et note si elles le sont avant ou après une mise à jour.
  • Un tableau de suivi montre les changements réels des variables, étape par étape.
  • Les points d’arrêt mettent l’exécution en pause ; les commandes de progression contrôlent la quantité de code exécutée ensuite.
  • breakpoint() ouvre pdb par défaut ; p, n, s, c et q sont des commandes du débogueur.
  • Examine les valeurs renvoyées lorsqu’une fonction affiche le bon résultat mais que son appelant échoue.
  • Supprime les affichages de diagnostic temporaires et les points d’arrêt après la correction.
4

Vérifier tes fonctions avec des tests

Les vérifications automatisées permettent de répéter un exemple utile chaque fois qu’une fonction change. Tu vas écrire des assertions avec des résultats attendus clairs, choisir des entrées aux limites d’une règle et empêcher les tests de lancer l’application qu’ils importent. Le framework standard unittest donne ensuite à chaque test un nom et un résultat distinct. La lecture de ses échecs et erreurs relie les tests au débogage : le test reproduit un problème et l’examen en trouve la cause.

4.1 Écrire des vérifications qui échouent lorsqu’une hypothèse est fausse

Une assertion énonce ce qui doit être vrai si ton code fonctionne correctement. Elle peut arrêter un bug près de son origine ou comparer le résultat d’une fonction à la valeur attendue.

Écrire une condition et un message facultatif
assert letter_grade(90) == "A", "90 should be an A"

Python évalue la condition. Si letter_grade(90) renvoie "A", la condition est vraie et l’exécution se poursuit sans affichage. Si elle renvoie "B", Python lève AssertionError avec le message 90 should be an A. La trace d’appels indique la vérification qui a échoué.

Sans le message, assert letter_grade(90) == "A" vérifie tout de même le résultat. La dernière ligne de l’exception contient AssertionError, tandis que la trace d’appels montre l’expression. Un message utile indique quelle attente n’a pas été satisfaite ; il doit t’aider à repérer la règle vérifiée.

Arrêter rapidement une erreur interne

Supposons qu’un calcul interne nécessite une liste non vide :

def average(values):
    assert len(values) > 0, "values must not be empty"
    return sum(values) / len(values)

Une liste vide déclenche désormais l’assertion avant la division. La vérification documente l’hypothèse interne de la fonction et indique directement quand elle n’est pas respectée. Elle ne donne pas de moyenne à une liste vide et ne décide pas comment une application doit réagir à l’absence de données utilisateur.

Maintenir active la validation des entrées utilisateur

L’option -O de Python supprime les instructions assert. Un programme qui utilise une assertion pour rejeter une entrée externe peut donc se comporter différemment lorsqu’il est optimisé. Vérifie les saisies utilisateur et les autres données externes avec les instructions de contrôle habituelles :

def require_score(score):
    if score < 0 or score > 100:
        raise ValueError("score must be 0 to 100")
    return score

Ici, raise ValueError(...) signale une valeur inadaptée. L’instruction if s’exécute toujours avec -O. Choisis une assertion pour une hypothèse interne au programme et une vérification active pour des données externes qui peuvent être incorrectes.

Éviter une vérification qui ne peut jamais échouer

assert est une instruction, pas une fonction. Écris la condition et le message séparés par une virgule :

assert x > 10, "x too small"

Écrire assert (x > 10, "x too small") crée un tuple à deux éléments. Un tuple non vide est vrai même si son premier élément vaut False : l’assertion réussit donc. Python peut avertir que cette assertion est toujours vraie. Des parenthèses autour de la seule condition, comme dans assert (x > 10), ne créent pas ce tuple ; c’est la virgule dans les parenthèses qui pose problème.

Utilise == pour comparer. assert total = 20 est une syntaxe invalide, car = affecte une valeur.

Comparer les nombres avec la précision voulue

Pour un flottant calculé, vérifie que les valeurs sont proches :

import math

assert math.isclose(0.1 + 0.2, 0.3)

Une comparaison exacte échoue ici, car la somme stockée sous forme de flottant diffère légèrement de 0.3. Un test automatisé simple applique la même idée d’assertion à une fonction : assert total_price([4, 6, 10]) == 20. La valeur attendue vient de la règle de la fonction : la vérification peut donc révéler une implémentation incorrecte.

Points clés

  • assert condition, message lève AssertionError lorsque sa condition est fausse.
  • Les assertions peuvent vérifier des hypothèses internes et les résultats attendus des fonctions.
  • Utilise if et un message d’erreur ou une exception pour les entrées externes ; -O supprime les assertions.
  • Une virgule dans assert (condition, message) crée un tuple dont la valeur de vérité est vraie.
  • Utilise == pour l’égalité et math.isclose pour comparer des flottants calculés.

4.2 Choisir des tests capables de révéler un bug

Un test unitaire vérifie une petite unité de code, généralement une fonction, avec une entrée choisie et un résultat attendu. Les tests automatisés rendent ces vérifications faciles à répéter après des modifications et aident à détecter les bugs qui réapparaissent dans un comportement auparavant correct.

Partir de la spécification

Supposons qu’une fonction de notation doive renvoyer "A" pour les notes d’au moins 90, "B" pour les notes d’au moins 80 mais inférieures à 90, et "C" en dessous de 80. La première condition erronée est score > 90.

Les tests doivent remplir plusieurs rôles :

  • Les cas typiques vérifient des entrées ordinaires à l’intérieur de chaque intervalle, comme 95 et 85.
  • Les cas aux limites vérifient les valeurs où une règle change, comme 90 et 89, ou 80 et 79.
  • Les cas extrêmes vérifient des entrées comme zéro ou une collection vide lorsque les règles de la fonction les autorisent.

Détermine la réponse attendue à partir de ces règles. Copier la réponse du programme actuel dans un test peut conserver son erreur.

Placer les tests à côté du module

Enregistre les tests dans test_grade.py et la fonction dans grade.py. Le lancement de l’application dans grade.py doit être placé sous sa garde __main__, afin que l’importation de la fonction ne lance pas le programme.

from grade import letter_grade

def test_letter_grade():
    assert letter_grade(95) == "A"
    assert letter_grade(90) == "A"
    assert letter_grade(85) == "B"

Avec la règle erronée, la première assertion réussit. La deuxième échoue parce que 90 n’est pas supérieur à 90 ; l’exécution s’arrête là, avant la troisième assertion de cette fonction. Remplacer la première condition par score >= 90 corrige cette limite. Relance tous les tests pour vérifier le cas concerné et le comportement antérieur.

S’assurer que les tests s’exécutent réellement

Définir une fonction de test ne l’appelle pas. Sans outil d’exécution des tests, ajoute test_letter_grade() à la fin du fichier de test, puis exécute python test_grade.py. Pour utiliser pytest, installe-le avec python -m pip install pytest, puis exécute pytest test_grade.py dans le terminal. Il trouve les fonctions de test et indique leurs résultats. N’ajoute pas d’appels manuels lorsque tu confies leur exécution à un outil de test.

Un test qui se contente d’appeler letter_grade(90) ne comporte aucune comparaison. Il peut se terminer avec succès alors que la réponse renvoyée est incorrecte ; il n’échoue que si l’appel lève une exception inattendue. Une assertion relie l’appel au comportement attendu.

Tester les valeurs renvoyées et les propriétés des résultats aléatoires

Une fonction qui se contente d’afficher un total renvoie None. Une comparaison comme assert print_total([4, 6]) == 10 échoue donc même si l’écran affiche 10. Fais renvoyer sa réponse par la fonction de calcul, puis laisse main gérer l’affichage.

Les résultats aléatoires nécessitent une autre attente. On ne peut pas exiger qu’une fonction simulant un dé sans graine fixée renvoie exactement la même face à chaque appel. Vérifie que chacun des 100 appels renvoie une valeur autorisée de 1 à 6, ou initialise la graine avant une séquence reproductible. Un test des bornes réussi vérifie les bornes pour ces appels ; il ne prouve pas que toutes les faces sont équiprobables.

Lorsqu’un nouveau bug apparaît, ajoute un test qui échoue à cause de ce bug avant de corriger la fonction. Garde ce test de régression pour que les modifications ultérieures vérifient à nouveau le même comportement. Des tests réussis établissent ce qui s’est passé pour les cas testés ; d’autres entrées peuvent encore révéler un autre bug.

Points clés

  • Détermine les résultats attendus à partir de la spécification, indépendamment de l’implémentation.
  • Teste des entrées ordinaires, les limites des règles et les cas extrêmes pertinents.
  • Les fonctions de test doivent être appelées ou exécutées par un outil de test ; leur définition seule n’effectue aucune vérification.
  • Les assertions doivent comparer les résultats renvoyés au comportement attendu.
  • Teste les propriétés adaptées des résultats aléatoires ou prépare une séquence reproductible.
  • Garde un test pour chaque nouveau bug découvert afin d’aider à détecter les régressions.

4.3 Exécuter et interpréter un fichier de test unittest

Python inclut unittest, un framework de test qui découvre les tests, les exécute et indique leurs résultats séparément. Il ne nécessite aucune installation avec pip. Sa structure de classe peut servir de modèle pendant que tu apprends à tester des fonctions.

Écrire des méthodes de test indépendantes

Pour une fonction dans grade.py, place ceci dans test_grade.py :

import unittest
from grade import letter_grade

class TestLetterGrade(unittest.TestCase):
    def test_top(self):
        self.assertEqual(letter_grade(95), "A")

    def test_boundary(self):
        self.assertEqual(letter_grade(90), "A")

    def test_low(self):
        self.assertEqual(letter_grade(50), "C")

if __name__ == "__main__":
    unittest.main()

TestLetterGrade hérite des outils de test de unittest.TestCase. Chaque test est une méthode dont le nom commence par test. self désigne l’objet test courant ; garde-le dans la liste des paramètres de chaque méthode et avant les appels aux méthodes d’assertion. Tu peux copier cette structure sans concevoir tes propres classes.

Par défaut, les tests s’exécutent par ordre alphabétique des noms de leurs méthodes : test_boundary vient donc avant test_low et test_top. Fais en sorte que chaque test fournisse ses propres entrées et fonctionne indépendamment des tests précédents.

Choisir une méthode d’assertion
MéthodeVérification
self.assertEqual(actual, expected)Les valeurs sont égales
self.assertNotEqual(a, b)Les valeurs diffèrent
self.assertTrue(condition)Une condition est vraie
self.assertFalse(condition)Une condition est fausse
self.assertIn(item, collection)L’élément appartient à la collection
self.assertAlmostEqual(a, b)La différence s’arrondit à zéro à 7 décimales par défaut

Privilégie assertEqual(a, b) à assertTrue(a == b) pour comparer des valeurs : le rapport d’échec affiche les deux valeurs. Les méthodes de unittest conservent aussi leurs vérifications lorsque Python s’exécute avec -O.

Pour vérifier une exception attendue, encadre l’appel avec assertRaises :

def test_score_too_high(self):
    with self.assertRaises(ValueError):
        letter_grade(120)

Ce test exige que la règle de la fonction rejette cette note avec ValueError. Un retour sans exception fait échouer cette vérification ; une exception différente d’une exception d’assertion constitue une erreur.

Exécuter les tests et lire le rapport

Exécute python test_grade.py pour lancer son unittest.main() protégé par la garde. Ou exécute python -m unittest pour découvrir les fichiers test*.py du dossier courant. python -m unittest -v affiche les noms des tests individuellement et leurs résultats.

Dans le rapport court, . signifie réussite, F signifie qu’une assertion a échoué et E qu’une autre exception s’est produite. Pour une fonction de notation avec score > 90, les trois tests ci-dessus produisent F... Le rapport d’échec de test_boundary montre 'B' != 'A' : le résultat obtenu est "B", tandis que le résultat attendu est "A". Le récapitulatif indique trois tests et un échec.

Avant de modifier la fonction, vérifie l’attente du test par rapport aux règles de notation. Une attente incorrecte nécessite une correction du test. Si aucun test ne s’exécute, examine les noms des méthodes, la garde d’exécution directe et la commande de lancement. Évite aussi de nommer ton fichier unittest.py, car il masque le module standard.

Points clés

  • Place les méthodes test dans une classe qui hérite de unittest.TestCase.
  • Utilise self.assertEqual et les autres méthodes d’assertion pour obtenir des vérifications et des rapports clairs.
  • assertRaises vérifie une exception attendue ; les comparaisons de flottants peuvent utiliser assertAlmostEqual.
  • Exécute directement un fichier de test protégé par une garde ou utilise python -m unittest pour découvrir les tests.
  • Lis F comme une assertion qui a échoué et E comme une autre exception.
  • Vérifie un test qui échoue par rapport à la spécification avant de modifier la fonction.
  • Chaque test doit fonctionner indépendamment de l’ordre alphabétique d’exécution.

Modules et débogage Python : exemples

4 Leçons Interactives

1

Construire un programme à partir d’éléments réutilisables

20 étapes
Choisir des importations et des fonctions de bibliothèque, réutiliser ton propre code et associer les paquets installés au Python qui les exécute.
  1. 1
    IntroductionPartir de code réutilisable

    Un programme peut appeler du code provenant de la bibliothèque standard de Python, d’un autre fichier que tu as écrit ou d’un paquet installé. La première question est de savoir quel nom le programme peut utiliser après l’importation.

    Tu vas suivre un calcul depuis son importation jusqu’à sa valeur de retour, puis organiser un module réutilisable et associer l’installation d’un paquet à son interpréteur. Au passage, vérifie si un résultat est une valeur à conserver ou une modification apportée à une liste existante.

  2. 2
    ExplicationL’importation détermine le style d’appel

    Ces importations rendent la même fonction accessible par des liaisons différentes :

    import math
    print(math.sqrt(16))
    
    from math import sqrt
    print(sqrt(16))
    

    Les deux affichent 4.0. La première crée math, donc l’appel utilise un point. La seconde crée sqrt, qui n’a donc pas besoin du préfixe du module. Utiliser le mauvais style d’appel lève NameError lorsque ce nom n’a pas été lié.

  3. 3
    ExempleCalculer l’hypoténuse

    Avec import math, pour un triangle rectangle de côtés 3 et 4, on peut utiliser :

    length = math.sqrt(3**2 + 4**2)
    

    Les carrés sont 9 et 16. Leur somme est 25, et math.sqrt(25) renvoie 5.0. Python évalue l’argument avant d’appeler la fonction.

    Le préfixe indique aussi au lecteur d’où vient sqrt. Une importation générique masque cette origine et peut remplacer des noms existants, comme une variable nommée e.

  4. 4
    DéfiSuivre la liaison de l’alias

    Un nouveau script exécute ces lignes. Que se passe-t-il à la dernière ligne et comment corriger le problème ?

    import statistics as st
    print(statistics.mean([4, 8, 12]))
    

    ---reveal---

    Le script lève NameError parce que l’importation lie st, pas statistics. Utilise st.mean([4, 8, 12]), qui renvoie 8. Un alias choisit la liaison dans ce programme ; il ne crée pas aussi le nom d’origine du module.

  5. 5
    ExempleArrondir pour obtenir suffisamment de contenants entiers

    Un mur de 23 mètres carrés doit être peint. Chaque pot couvre 10 mètres carrés.

    import math
    cans = math.ceil(23 / 10)
    

    La division donne 2.3 ; ceil donne 3, soit suffisamment de pots entiers. round(2.3) ne donne que 2.

    Pour les entrées négatives, l’arrondi inférieur va toujours vers l’infini négatif : math.floor(-2.5) vaut -3, tandis que int(-2.5) tronque vers zéro et donne -2.

  6. 6
    Point cléAdapter la comparaison au nombre

    Les flottants calculés peuvent différer légèrement des valeurs décimales attendues :

    0.1 + 0.2 == 0.3               # False
    math.isclose(0.1 + 0.2, 0.3)   # True
    

    Vérifie que les valeurs sont proches pour effectuer cette comparaison approchée. Par ailleurs, les entrées autorisées pour une fonction comptent toujours : math.sqrt(-1) lève ValueError.

    La fonction native round ne nécessite aucune importation. Pour une valeur exactement à mi-chemin, elle choisit l’entier pair voisin : round(2.5) vaut 2 et round(3.5) vaut 4.

  7. 7
    ExplicationChoisir le résultat aléatoire nécessaire

    Après import random, choisis un appel selon son rôle :

    • randint(1, 6) choisit un entier en incluant 6.
    • randrange(1, 6) choisit un entier en excluant 6.
    • random() donne un flottant de 0,0 inclus à 1,0 exclu.
    • choice(items) choisit un élément.
    • sample(items, k) choisit k positions sans remise.

    Deux positions sélectionnées peuvent contenir la même valeur. Tirer les deux positions de [1, 1] donne donc des 1 répétés.

  8. 8
    DéfiConserver la liste mélangée

    Quelle valeur names contient-il à la fin et comment modifier la dernière ligne pour conserver la liste ?

    names = ["Mina", "Luis", "Jo"]
    names = random.shuffle(names)
    

    ---reveal---

    Il contient None. shuffle modifie la liste existante, puis renvoie None ; l’affectation remplace la liaison à la liste par cette valeur de retour. Utilise random.shuffle(names) sur sa propre ligne. Le nouvel ordre de la liste est aléatoire, mais la valeur renvoyée est toujours la même.

  9. 9
    LienRépéter une simulation et trouver d’autres outils

    Appelle random.seed(42) avant de générer des valeurs pour répéter la même séquence avec la même version de Python. Cela facilite la reproduction d’un échec aléatoire. Utilise secrets pour les jetons de sécurité.

    D’autres modules standard accomplissent des tâches courantes : statistics.mean([2, 4, 9]) donne 5, et median donne 4. datetime.date.today() donne la date du jour. sys.argv liste le nom du script exécuté suivi de ses arguments de ligne de commande.

  10. 10
    ExemplePlacer une fonction réutilisable dans un module

    Enregistre ceci sous le nom geometry.py :

    import math
    
    def circle_area(radius):
        """Return the circle's area."""
        return math.pi * radius ** 2
    

    Un script situé dans le même dossier peut exécuter import geometry, puis print(geometry.circle_area(2)). Il affiche 12.566370614359172.

    Importe le fichier sans .py. La première chaîne de la fonction est sa docstring, que help(geometry.circle_area) peut afficher.

  11. 11
    ExplicationUne importation exécute les instructions de premier niveau

    Supposons que geometry.py se termine par print(circle_area(2)), hors d’une fonction. Sa première importation affiche l’aire comme effet de bord.

    Python exécute dans l’ordre les instructions de premier niveau du module. Définir circle_area crée la fonction sans exécuter son corps ; l’appeler dans l’affichage de premier niveau exécute le calcul. Une deuxième importation dans le même processus réutilise le module chargé. Une console interactive conserve aussi cette version chargée après la modification du fichier, jusqu’à son redémarrage.

  12. 12
    ExempleLancer uniquement lors d’une exécution directe

    Laisse la fonction réutilisable au-dessus de ce bloc :

    def main():
        print(circle_area(2))
    
    if __name__ == "__main__":
        main()
    

    Une exécution directe donne à __name__ la valeur "__main__", donc main() s’exécute. Une importation lui donne la valeur "geometry", donc le lancement est ignoré.

    Les définitions restent disponibles dans les deux cas. Un test peut ainsi importer circle_area sans produire la sortie habituelle du programme.

  13. 13
    DéfiGarder la fonction accessible au programme qui l’importe

    Un fichier définit convert dans son bloc if __name__ == "__main__":. Un nouveau processus de test importe le fichier et ne trouve pas convert. Quelle organisation permet à la fois la réutilisation et le lancement lors d’une exécution directe ?

    ---reveal---

    Déplace def convert(...) hors de la garde et ne garde que le lancement du programme à l’intérieur. Lors de l’importation, la garde est fausse : une définition placée à l’intérieur est donc ignorée. Déplacer la définition la rend accessible sans lancer l’application.

  14. 14
    ConseilVérifier le fichier trouvé par une importation

    Python vérifie les modules intégrés, puis parcourt sys.path dans l’ordre. Le dossier du script apparaît normalement avant les dossiers de bibliothèque. Un fichier local random.py peut donc masquer le module random que tu voulais importer.

    Renomme ce fichier, par exemple en dice.py. Pour tes propres fonctions auxiliaires, utilise des noms valides comme my_tools.py et garde les fichiers à côté du script de débutant qui les importe. Une importation ordinaire ne trouve pas un fichier situé hors du chemin de recherche.

  15. 15
    ExempleInstaller dans le terminal, importer dans Python

    Dans le terminal, exécute :

    python -m pip install cowsay
    

    Le code Python peut ensuite utiliser :

    import cowsay
    cowsay.cow("Hello, Ada")
    

    Le paquet affiche une vache dessinée avec des caractères et une bulle. pip installe le code, tandis que import crée la liaison utilisée par ton programme. La commande d’installation n’est pas une instruction Python ; à l’invite >>>, elle produit une erreur de syntaxe.

  16. 16
    ExplicationUtiliser le pip associé au Python qui exécute le programme

    Si un script s’exécute avec python3, effectue l’installation avec la même commande :

    python3 -m pip install cowsay
    python3 game.py
    

    -m pip sélectionne le pip associé à cet interpréteur. Sous Windows, ta commande peut être py.

    Si l’éditeur ne peut pas importer un paquet pourtant installé, compare l’interpréteur qu’il a sélectionné avec celui utilisé dans le terminal. Une installation réussie dans un Python n’installe pas le paquet dans tous les autres.

  17. 17
    DéfiDistinguer le nom d’installation du nom d’importation

    La documentation d’un paquet indique d’installer Pillow et d’importer PIL. L’installation réussit pour le Python que tu utilises, mais import Pillow échoue. Que faut-il changer et pourquoi ?

    ---reveal---

    Utilise import PIL. Le nom de distribution utilisé par pip peut différer du nom d’importation Python qu’il fournit. Puisque la correspondance entre les interpréteurs est déjà établie, répéter la même commande d’installation laisserait cette erreur de nom en place.

  18. 18
    ConseilExaminer un paquet avant de le modifier

    python -m pip list affiche les versions installées. show requests donne la version et l’emplacement d’un paquet ; install --upgrade requests le met à jour et uninstall requests le supprime. Chaque commande courte suit python -m pip.

    Vérifie le nom exact sur PyPI et la documentation du projet avant l’installation. En cas d’erreur externally-managed-environment, utilise un environnement virtuel pour le projet ; ne force pas l’installation avec sudo pip install.

  19. 19
    DéfiPrévoir une importation et un appel ultérieur

    Un nouveau module sizes.py contient ce code. Un autre script exécute from sizes import batches, puis print(batches(17)). Qu’est-ce qui s’affiche ?

    import math
    
    def batches(n):
        return math.ceil(n / 5)
    
    if __name__ == "__main__":
        print(batches(12))
    

    ---reveal---

    Seul 4 s’affiche. L’importation crée la fonction mais ignore l’affichage protégé par la garde. L’appel ultérieur divise 17 par 5, puis arrondit 3,4 à l’entier supérieur, soit 4. La liaison math dans sizes est accessible à sa fonction.

  20. 20
    RécapitulatifSuivre le code depuis sa source jusqu’à l’appel

    Choisis une importation qui correspond aux noms que tu veux utiliser. Vérifie ce que renvoie un appel de bibliothèque, notamment un éventuel None pour une opération qui modifie une liste.

    Garde les définitions réutilisables accessibles pendant l’importation et place le lancement de l’application derrière la garde du programme principal. Pour le code installé, associe pip à l’interpréteur qui exécute le programme et vérifie le nom d’importation indiqué dans la documentation. Lorsqu’un appel échoue, ces détails aident à distinguer une liaison manquante, un attribut manquant et une installation manquante.

2

Remonter d’un échec à sa cause

11 étapes
Lire les cadres d’appels, reconnaître les exceptions courantes et distinguer un arrêt d’un résultat incorrect qui ne produit aucun message d’erreur.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionUtiliser le rapport comme indice
  2. 2
    ExempleUne liste vide arrive à une division
  3. 3
    ExplicationTrouver le cadre le plus récent
  4. 4
    ExempleRemonter le parcours de l’argument à travers ses appelants
  5. 5
    DéfiLocaliser un argument inadapté
  6. 6
    ExplicationDistinguer grammaire, types et valeurs
  7. 7
    ExplicationDes accès différents produisent des erreurs différentes
  8. 8
    ExempleUn calcul peut se terminer normalement avec un total incorrect
  9. 9
    DéfiExpliquer l’échec d’une addition
  10. 10
    DéfiUtiliser un cadre de bibliothèque sans mettre en cause la bibliothèque
  11. 11
    RécapitulatifChoisir le prochain endroit à examiner
3

Examiner un bug, des indices à la correction

14 étapes
Reproduire un total incorrect, examiner sa boucle, effectuer une correction ciblée et utiliser les commandes d’un débogueur pour suivre un appel de fonction.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionReproduire le résultat incorrect
  2. 2
    ExempleIndiquer les résultats attendu et obtenu
  3. 3
    ExplicationRendre l’hypothèse vérifiable
  4. 4
    ExempleAfficher avant la mise à jour
  5. 5
    ExempleSuivre les additions à la main
  6. 6
    DéfiInterpréter un affichage après la mise à jour
  7. 7
    ExempleCorriger le parcours lui-même
  8. 8
    LienTester à nouveau des entrées de formes différentes
  9. 9
    ConseilRéduire un échec plus complexe
  10. 10
    DéfiVérifier une valeur qui ressemble à un nombre
  11. 11
    ExplicationMettre en pause à l’appel à examiner
  12. 12
    DéfiChoisir la commande de progression
  13. 13
    DéfiExaminer un affichage correct et une valeur de retour incorrecte
  14. 14
    RécapitulatifRelier la correction aux indices
4

Transformer un bug de limite en test durable

16 étapes
Écrire des assertions, choisir des entrées qui révèlent les erreurs et utiliser unittest pour exécuter des vérifications indépendantes et interpréter leurs résultats.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionVérifier le comportement attendu de façon reproductible
  2. 2
    ExplicationUne assertion énonce une attente
  3. 3
    DéfiTrouver une vérification qui ne peut pas échouer
  4. 4
    Point cléMaintenir actives les vérifications des entrées externes
  5. 5
    ExempleChoisir des entrées autour du changement de note
  6. 6
    ExempleÉcrire une fonction de test qui importe le code
  7. 7
    ConseilExécuter les vérifications définies
  8. 8
    DéfiCorriger un seuil et conserver la vérification
  9. 9
    LienTester le résultat renvoyé ou une propriété valide
  10. 10
    ExempleUtiliser le modèle de classe unittest
  11. 11
    ExplicationChoisir l’assertion adaptée au résultat
  12. 12
    ExempleLire une vérification de note qui a échoué
  13. 13
    DéfiDistinguer un échec de test d’une erreur
  14. 14
    ConseilVérifier ce que la découverte des tests a réellement exécuté
  15. 15
    DéfiUtiliser un rapport pour préparer la correction
  16. 16
    RécapitulatifConserver un test pour le comportement corrigé

Modules et débogage Python : QCM

40 Questions Pratiques en 4 séries

Série 1 : Modules, choix de débogage et résultats des tests10 Questions Pratiques

Question 1 sur 10

Après import statistics as st, la ligne suivante est statistics.mean([3, 7]). Il n’y a aucune autre importation ni affectation. Qu’est-ce qui explique l’erreur ?
  1. La fonction mean nécessite aussi import math.
  2. Seul st a été lié ; appelle st.mean([3, 7]).
  3. Seul mean a été lié ; appelle mean([3, 7]).
  4. L’alias doit être transmis avec statistics.mean(st).
Afficher la réponseMasquer la réponse
Réponse : B
La forme avec alias lie le module à st dans ce script. Elle ne lie pas aussi statistics : le nom d’origine du module, utilisé seul, lève donc NameError. mean([3, 7]) seul échouerait aussi, car importer un module sous un alias n’importe pas directement les noms de ses fonctions.

Question 2 sur 10

Quelle est la valeur de tickets après ce code ?

import random
tickets = [11, 22, 33]
tickets = random.shuffle(tickets)
  1. Une nouvelle liste mélangée de trois éléments
  2. Le premier élément de la liste mélangée
  3. La liste d’origine dans son ordre initial
  4. None
Afficher la réponseMasquer la réponse
Réponse : D
shuffle réorganise la liste existante, puis renvoie None. L’affectation remplace la liaison de tickets par cette valeur de retour : le nom ne désigne donc plus la liste. Pour garder la liaison, appelle random.shuffle(tickets) sur sa propre ligne au lieu d’affecter le résultat.

Question 3 sur 10

Un module auxiliaire définit double, puis contient la ligne non protégée print(double(6)). Un autre script l’importe deux fois au cours d’une exécution. Combien de fois cette ligne produit-elle un affichage ?
  1. Une fois, lors de la première importation
  2. Deux fois, une fois par instruction d’importation
  3. Jamais, car les importations ne lisent que les noms de fonctions
  4. Une fois, seulement si le script appelle ensuite double
Afficher la réponseMasquer la réponse
Réponse : A
La première importation exécute les instructions de premier niveau du module auxiliaire, dont cet affichage. La seconde réutilise le module chargé : elle n’exécute donc pas à nouveau la ligne. L’importation ne se limite pas à recueillir les noms des fonctions : les appels de premier niveau non protégés s’exécutent aussi.

Question 4 sur 10

Un éditeur exécute un script avec Python A. La commande de terminal python -m pip show cowsay indique un emplacement dans Python B, et l’éditeur ne peut pas importer cowsay. Que dois-tu faire en premier ?
  1. Relancer sans modification l’installation pip de Python B.
  2. Remplacer l’importation par le chemin du dossier du paquet.
  3. Exécuter -m pip install cowsay avec Python A.
  4. Déplacer le script dans le répertoire de bibliothèque de Python B.
Afficher la réponseMasquer la réponse
Réponse : C
Les détails de l’installation montrent que pip a agi sur Python B alors que l’éditeur utilise Python A. Exécuter pip avec A installe le paquet pour l’interpréteur qui en a besoin. Répéter sans la modifier la commande utilisant B agirait sur la même autre installation et ne résoudrait pas le décalage.

Question 5 sur 10

Une trace d’appels contient trois cadres. Où trouves-tu d’abord le type d’exception et le message ?
  1. Dans le premier cadre, près du nom du script
  2. Dans l’en-tête au-dessus du premier cadre
  3. Sur la ligne contenant l’appel le plus ancien
  4. Sur la dernière ligne, sous les cadres
Afficher la réponseMasquer la réponse
Réponse : D
La dernière ligne indique l’exception et son message, ce qui donne le premier indice sur l’opération qui a échoué. Le cadre du bas montre ensuite l’emplacement de code le plus récent. Commencer par le cadre le plus ancien indique comment l’exécution a commencé, mais pas encore quelle opération a échoué.

Question 6 sur 10

Cette fonction doit additionner toutes les quantités. Quel type de problème explique le résultat de total([2, 5, 8]) ?

def total(values):
    result = 0
    for i in range(1, len(values)):
        result += values[i]
    return result
  1. Une IndexError se produit car la boucle atteint l’indice 3.
  2. Une erreur de logique renvoie 13 car l’indice 0 est ignoré.
  3. Une TypeError se produit car les éléments d’une liste ne peuvent pas être additionnés.
  4. Une erreur de syntaxe se produit car range nécessite trois arguments.
Afficher la réponseMasquer la réponse
Réponse : B
La boucle parcourt les indices 1 et 2 : elle additionne donc 5 et 8 et renvoie 13. Les deux indices existent ; la borne de fin exclue empêche un accès à l’indice 3. Le code est valide et s’exécute, mais sa valeur de départ fait ignorer la première quantité : c’est une erreur de logique.

Question 7 sur 10

Un programme de traitement de données qui échoue comporte 300 lignes et 200 enregistrements. Qu’est-ce qui constitue un exemple minimal reproductible utile ?
  1. Le code complet avec tous les enregistrements et affichages de diagnostic
  2. La réponse attendue avec l’entrée qui échoue entièrement supprimée
  3. Le code le plus court et la plus petite entrée qui échouent encore
  4. Un programme réécrit dont la sortie a déjà été corrigée
Afficher la réponseMasquer la réponse
Réponse : C
Un exemple minimal conserve l’échec tout en supprimant le code et les données sans rapport. Il devient ainsi plus facile de suivre les valeurs qui déclenchent le bug et de donner aux autres assez d’informations pour le reproduire. Supprimer l’entrée qui échoue peut raccourcir l’exemple, mais aussi supprimer les indices nécessaires à l’examen.

Question 8 sur 10

Une vérification d’entrée utilise assert (score >= 0, "negative score"). Elle réussit lorsque score vaut -3. Quelle modification corrige la vérification tout en gardant la validation active avec -O ?
  1. if score < 0: raise ValueError("negative score")
  2. assert score >= 0, "negative score"
  3. assert (score < 0, "negative score")
  4. assert (score >= 0) == True
Afficher la réponseMasquer la réponse
Réponse : A
La condition d’origine est un tuple non vide, qui est vrai même lorsque son premier élément est faux. Une assertion correctement écrite corrigerait cette erreur de tuple, mais -O la supprimerait tout de même. Un if qui lève ValueError vérifie l’entrée externe aussi bien en exécution normale qu’en exécution optimisée.

Question 9 sur 10

Un fichier de test ordinaire définit test_discount, qui contient deux assertions, mais ne l’appelle jamais. Tu exécutes ce fichier avec python test_discount.py ; il ne contient aucun code d’exécution des tests. Pourquoi aucune assertion n’est-elle vérifiée ?
  1. Python supprime chaque assertion de tout fichier test_.
  2. Chaque assertion doit être déplacée au-dessus de la fonction.
  3. Définir la fonction n’exécute pas son corps.
  4. La fonction de test doit renvoyer True avant d’être appelée.
Afficher la réponseMasquer la réponse
Réponse : C
Une définition de fonction crée la fonction mais n’exécute pas son corps. Appelle test_discount() dans un fichier exécuté directement ou laisse un outil de test la découvrir. Python ne supprime pas les assertions simplement parce que le nom du fichier commence par test_ ; le problème est ici l’absence d’exécution.

Question 10 sur 10

Une méthode unittest appelle self.assertEqual(lookup("x"), 7). L’appel à lookup lève une KeyError inattendue avant de renvoyer une valeur. Quel symbole marque le résultat de ce test ?
  1. F, car tout problème dans un test est un échec d’assertion
  2. E, car une autre exception a interrompu la vérification
  3. ., car aucune comparaison d’égalité n’a donné faux
  4. F, car KeyError est identique à AssertionError
Afficher la réponseMasquer la réponse
Réponse : B
La KeyError inattendue empêche l’assertion d’égalité de comparer les valeurs renvoyées : unittest enregistre donc une erreur, indiquée par E. Une assertion d’égalité fausse produirait F. Le simple fait de ne pas atteindre une comparaison ne fait pas réussir un test lorsqu’une exception inattendue se produit.
Série 2 : Importations, indices d’erreur et premières vérifications10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un script contient uniquement import math avant son calcul. Comment doit-il appeler la fonction racine carrée sur 81 ?
  1. sqrt(81)
  2. math(81).sqrt()
  3. math.sqrt(81)
  4. import.sqrt(81)
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une navette peut transporter 8 personnes. Que renvoie math.ceil(35 / 8) et que représente ce résultat ?
  1. 5, le nombre de navettes nécessaires pour tous
  2. 4, le nombre de navettes nécessaires pour tous
  3. 4.375, le nombre de navettes à réserver
  4. 4, le nombre de places laissées vides
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un fichier nommé text_tools.py définit shorten. Comment un autre fichier du même dossier peut-il l’importer et l’appeler ?
  1. import text_tools.py, puis text_tools.shorten("Hello")
  2. import shorten, puis shorten.text_tools("Hello")
  3. import text_tools, puis shorten.text_tools("Hello")
  4. import text_tools, puis text_tools.shorten("Hello")
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Tu es à l’invite Python >>> et tu saisis pip install cowsay. Pourquoi Python signale-t-il une syntaxe invalide ?
  1. Le paquet doit être importé avant de pouvoir être installé.
  2. La commande d’installation doit être saisie dans le terminal.
  3. Le nom du paquet doit être écrit avec la terminaison .py.
  4. La commande d’installation nécessite une affectation Python.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une trace d’appels se termine par ZeroDivisionError. Ses cadres montrent, de haut en bas, show([]), mean(data) et sum(values) / len(values). Quel enchaînement explique le mieux l’échec ?
  1. La fonction show a tenté de diviser son propre nom par zéro.
  2. Une liste vide est arrivée à mean, rendant son diviseur nul.
  3. La liste est devenue vide car la trace s’affiche à l’envers.
  4. La somme était nulle, ce qui rend toujours la division invalide.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Quelle exception int("7.25") lève-t-il ?
  1. TypeError
  2. NameError
  3. IndexError
  4. ValueError
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une fonction devrait donner un total de 16 pour [9, 2, 5], mais elle renvoie 7. Tu soupçonnes qu’elle ignore le premier élément. Quelle observation permettrait de tester cette idée le plus directement ?
  1. Relever les indices parcourus par la boucle de somme.
  2. Afficher à nouveau le total attendu après l’appel de fonction.
  3. Ajouter 9 au résultat et vérifier uniquement cette même entrée.
  4. Renommer la variable du total et relancer sans rien examiner.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Quelles sont les deux lignes affichées ?

total = 0
for n in [3, 8]:
    print(f"{n=} {total=}")
    total += n
  1. n=3 total=3, puis n=8 total=11
  2. n=3 total=0, puis n=8 total=0
  3. n=3 total=0, puis n=8 total=3
  4. n=0 total=3, puis n=3 total=8
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Que se passe-t-il lorsque ce code s’exécute normalement ?

count = 6
assert count < 5, "too many"
print("saved")
  1. Il lève AssertionError avec "too many".
  2. Il affiche "saved", puis signale l’assertion.
  3. Il affecte 5 à count et continue sans affichage.
  4. Il affiche "too many", puis affiche "saved".
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

La règle prévoit la gratuité jusqu’à un poids de 12 inclus, des frais de 4 de 13 à 18 inclus, et des frais de 7 au-dessus de 18. Les tests pour 5 et 20 réussissent. Quels résultats et quelle modification permettent de diagnostiquer correctement ce code ?

def fee(weight):
    if weight < 12:
        return 0
    if weight <= 18:
        return 4
    return 7
  1. À 12 : 0 ; à 18 : 7. Remplacer le second test par < 18.
  2. À 12 : 4 ; à 18 : 7. Remplacer les deux comparaisons par <.
  3. À 12 : 0 ; à 18 : 4. Garder les deux comparaisons inchangées.
  4. À 12 : 4 ; à 18 : 4. Remplacer le premier test par <= 12.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Suivre les causes à travers les modules et les tests10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Qu’affiche ce code ?

from math import sqrt as root
sqrt = 4
result = root(sqrt ** 2)
print(result, sqrt)
  1. 16.0 4
  2. 4.0 4.0
  3. Il lève TypeError parce que sqrt est un entier.
  4. 4.0 4
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Un tirage utilise random.sample(["blue", "blue", "red"], 2). Pourquoi le résultat peut-il contenir deux valeurs "blue" ?
  1. Le tirage remet toujours le premier élément avant de tirer à nouveau.
  2. Les deux éléments bleus occupent des positions différentes dans l’entrée.
  3. La valeur 2 demande deux copies identiques d’un élément choisi.
  4. Le tirage ne supprime les valeurs en double qu’après les avoir renvoyées.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un module contient ce code. Un nouveau processus l’importe, puis appelle helper.answer(). Que se passe-t-il ?

# helper.py
if __name__ == "__main__":
    def answer():
        return 42
  1. Il renvoie 42 car Python charge d’abord toutes les définitions.
  2. NameError : Python ne définit jamais __name__ à l’importation.
  3. AttributeError : l’importation a ignoré la définition de la fonction.
  4. Il renvoie None car la garde modifie les valeurs de retour.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une trace d’appels commence par ton appel run_report(), puis ton appel parse(raw), et se termine dans une conversion de bibliothèque avec ValueError. Tu examines raw à ton appel de parse et trouves "9x", alors que la règle exige un texte représentant un entier. Où poursuivre l’examen ?
  1. Remonter pour voir où raw est devenu "9x" avant l’appel de parse.
  2. Remplacer int(raw) par int(raw[0]) pour obtenir un nombre avec cette entrée.
  3. Considérer le cadre de bibliothèque comme une preuve de défaut et modifier sa conversion.
  4. Garder l’entrée et réinstaller la bibliothèque puisque l’appelant s’est déjà exécuté.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une fonction affiche 18 mais ne possède pas d’instruction return. Son appelant évalue ensuite result + 2, où result est la valeur renvoyée par l’appel. Pourquoi une TypeError se produit-elle ?
  1. result vaut None, qui ne peut pas être ajouté à 2.
  2. result est la chaîne "18" car l’affichage convertit les valeurs renvoyées.
  3. result vaut 18, mais additionner deux entiers est invalide ici.
  4. result est indéfini car chaque affichage supprime sa liaison.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une suite de traitements lit, convertit et totalise des données. Pour un échec reproductible, les valeurs nécessaires au total sont déjà incorrectes juste après la conversion. La lecture seule produit les valeurs brutes attendues. Quel est l’examen suivant le plus ciblé ?
  1. Ajouter une correction au total final et laisser la conversion inchangée.
  2. Réécrire les trois étapes ensemble et comparer uniquement la sortie finale.
  3. Exécuter la conversion seule sur la plus petite entrée brute qui échoue.
  4. Examiner uniquement l’affichage final, où apparaît la sortie incorrecte.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Un débogueur est en pause sur answer = calculate(7). Tu veux examiner la première ligne à l’intérieur de calculate. Quelle commande dois-tu utiliser ?
  1. Pas à pas principal
  2. Pas à pas détaillé
  3. Sortie de fonction
  4. Continuer
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

La règle indique qu’un trajet est gratuit pour les distances jusqu’à 6 inclus et coûte 3 au-dessus de 6. charge(6) renvoie 3, mais son test attend 3 et réussit. Quelle modification crée un test de régression utile et corrige la règle ?
  1. Garder 3 à 6, puis ajouter seulement un test pour un trajet payant éloigné.
  2. Modifier la règle pour rendre 6 payant, puis garder le test existant.
  3. Supprimer la vérification à 6, puis comparer seulement deux exemples réussis.
  4. Attendre 0 à 6, constater l’échec, puis corriger et relancer les tests.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un fichier unittest contient test_alpha, qui attend 4 mais reçoit 5, test_beta, qui réussit, et test_gamma, qui lève une TypeError inattendue. Quelle chaîne compacte de progression l’exécution alphabétique par défaut produit-elle ?
  1. E.F
  2. F.E
  3. F.F
  4. .FE
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un unittest.TestCase contient check_empty, avec une vérification d’égalité qui échoue, et test_full, avec une vérification qui réussit. L’outil d’exécution indique un test et OK. Comment faire exécuter la vérification de comportement manquante ?
  1. Renommer check_empty en test_empty et relancer les tests.
  2. Ajouter return False à la fin de check_empty.
  3. Déplacer check_empty sous test_full dans la classe.
  4. Remplacer assertEqual par print dans check_empty.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Combiner les décisions d’importation, de débogage et de test10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une simulation initialise la graine une fois, puis appelle random.randint(2, 5) 50 fois. Un nouveau test initialise la graine à la même valeur avec la même version de Python et répète les mêmes appels. Que doivent attendre ses vérifications ?
  1. La séquence se répète et chaque résultat est compris entre 2 et 5 inclus.
  2. La séquence se répète et chaque résultat est compris entre 2 et 4 inclus.
  3. Chaque résultat apparaît aussi souvent et les quatre valeurs doivent apparaître.
  4. Chaque appel redonne le premier résultat puisque la graine reste définie.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

La documentation indique beautifulsoup4 comme distribution et bs4 comme module. Un script importe bs4 avec succès. Un collègue veut modifier python -m pip install beautifulsoup4 pour installer bs4 afin que les noms correspondent. Cette correspondance est-elle une raison valable de faire ce changement ?
  1. Oui ; toute importation réussie doit utiliser le nom d’installation de la distribution.
  2. Oui ; importer bs4 prouve que pip a installé une distribution sous ce nom.
  3. Non ; l’installation suit le nom documenté de la distribution, qui peut différer.
  4. Non ; le module doit d’abord être renommé pour correspondre à la distribution actuelle.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une nouvelle exécution de display.py indique ces appels, de haut en bas : start(" "), read_count(text), puis int(text), et se termine par ValueError. Quelle suite d’actions permet le mieux de tester la cause probable avant une correction ?
  1. Examiner seulement type(text) ; recevoir une chaîne suffit à établir une erreur de type.
  2. Examiner repr(text), confirmer l’entrée vide, puis définir le comportement pour cette entrée.
  3. Déplacer la même conversion dans start pour l’exécuter avant les autres appels.
  4. Remplacer chaque conversion échouée par zéro sans vérifier le comportement requis.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une fonction de total ignore le premier élément. Un correctif ajoute 6 à chaque total renvoyé et réussit maintenant pour [6, 3, 2]. Quels résultats attendus et obtenus pour deux nouvelles entrées révèlent le problème restant ?
  1. [9] : attendu 9, obtenu 15 ; [] : attendu 0, obtenu 6.
  2. [9] : attendu 9, obtenu 6 ; [] : attendu 0, obtenu 0.
  3. [9] : attendu 6, obtenu 6 ; [] : attendu 6, obtenu 6.
  4. [9] : attendu 9, obtenu 6 ; [] : attendu 0, obtenu 6.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Cette fonction affiche un produit correct, mais son appelant reçoit une TypeError dans area(4, 5) + 1. Où dois-tu examiner l’exécution et quel résultat explique l’échec ?

def area(w, h):
    product = w * h
    print(product)
  1. Exécuter l’appel en pas à pas principal ; il renvoie l’entier 20.
  2. Exécuter l’appel en pas à pas principal ; il renvoie la chaîne "20".
  3. Exécuter l’appel en pas à pas principal ; il renvoie None.
  4. Entrer dans l’appel en pas à pas détaillé ; son affichage devient la valeur de retour.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Que se passe-t-il lors d’une exécution ordinaire, sans optimisation ?

import math
assert math.isclose(0.1 + 0.2, 0.3)
assert 0.1 + 0.2 == 0.3
  1. La première assertion réussit ; la seconde lève AssertionError.
  2. Les deux assertions réussissent car les sommes décimales sont stockées exactement.
  3. La première assertion échoue ; la seconde ne s’exécute jamais.
  4. Les deux assertions échouent, mais le programme continue jusqu’à la fin.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

pick() renvoie un entier aléatoire de 3 à 7, bornes comprises. pair_total() additionne les résultats de deux appels à pick(). Un test qui affirme que chaque total obtenu sans graine fixée vaut 10 échoue parfois alors que les deux fonctions fonctionnent correctement. Quelle vérification de chaque résultat correspond à l’intervalle requis pour le total ?
  1. Vérifier par assertion 3 <= value <= 7 pour chaque total.
  2. Vérifier par assertion 6 <= value < 14 pour chaque total.
  3. Vérifier par assertion value == 10 pour chaque total.
  4. Vérifier par assertion 6 <= value <= 14 pour chaque total.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

reserve(n) doit accepter les nombres entiers de 0 à 8 inclus et lever ValueError hors de cet intervalle. Des tests utilisant assertRaises(ValueError) indiquent F pour -1 parce qu’aucune exception ne se produit, et E pour 9 parce qu’une TypeError se produit. Un test à 2 réussit. Quel comportement la correction doit-elle assurer ?
  1. Accepter -1 normalement ; lever ValueError à 9 ; garder 2 valide.
  2. Lever ValueError à -1 et à 9 ; garder 2 valide.
  3. Lever ValueError à -1 ; garder TypeError à 9 ; garder 2 valide.
  4. Accepter -1 et 9 normalement ; lever ValueError à 2.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un script est nommé random.py et importe random, puis échoue parce que random.randint est absent. Quelle première modification traite le conflit de noms ?
  1. Installer à nouveau le module random avec pip.
  2. Déplacer import random sous l’appel à randint.
  3. Garder random.py et utiliser from random import randint.
  4. Renommer le script en draw_numbers.py.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un programme contient assert total == 10 pour un calcul interne et assert age >= 0 pour une saisie utilisateur. Il s’exécute avec -O, avec total égal à 9 et age égal à -1. Qu’arrive-t-il à ces vérifications et quelle modification maintient la validation requise de la saisie ?
  1. Seule la vérification du total disparaît ; ajouter un message plus long à l’assertion sur l’âge.
  2. Les deux vérifications disparaissent ; placer la condition sur l’âge et le message dans un tuple.
  3. Les deux vérifications disparaissent ; utiliser if age < 0 et une réponse d’erreur pour la saisie.
  4. Seule la vérification de l’âge disparaît ; la déplacer dans une fonction nommée test_age.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

60 Mots-Clés, chacun avec sa définition

A

Alias
Un alias est le nom choisi avec as pour un module ou un objet importé ; l’importation lie ce nom dans le programme qui importe.
L’alias stats dans import statistics as stats permet au script d’appeler stats.mean([1, 3, 8]).
Assertion
Une assertion vérifie une condition qui doit être vraie si le code est correct : elle poursuit l’exécution si la condition est vraie et lève AssertionError si elle est fausse.
Une assertion comme assert count == 3 compare un résultat interne au nombre attendu que tu as déterminé indépendamment.
AssertionError
Une AssertionError signale une assertion qui a échoué et peut inclure un message fourni expliquant quelle attente la vérification n’a pas satisfaite.
Une AssertionError avec "wrong total" attire l’attention sur le test qui a comparé le total calculé.

B

Bibliothèque standard
La bibliothèque standard est la collection de modules inclus avec Python, qui fournit des outils prêts à l’emploi sans installation séparée de paquet.
La bibliothèque standard comprend math pour les calculs et random pour les simulations, comme les lancers de dés.
Bug
Un bug est une erreur qui fait différer le comportement d’un programme de celui qui était prévu, notamment par des réponses incorrectes ou des échecs inattendus.
Un bug qui ignore le premier prix peut être reproduit avec une liste à un élément dont le total attendu est facile à vérifier.

C

Cadre d’exécution
Un cadre d’exécution dans une trace d’appels indique l’emplacement d’un appel actif par son fichier, son numéro de ligne et sa fonction, avec la ligne de code source concernée.
Le cadre le plus bas peut montrer une division par la longueur d’une liste vide, tandis que les cadres précédents révèlent quel appelant a fourni cette liste.
Cas extrême
Un cas extrême est une entrée inhabituelle située à une limite extrême ou particulière, comme une liste vide, qui peut révéler un comportement que les entrées ordinaires ne révèlent pas.
Un cas extrême utilisant une liste à un élément peut révéler qu’une fonction de total commence sa boucle au deuxième élément.
Cas limite
Un cas limite est une entrée de test située à une limite où une règle change, ce qui facilite la détection des erreurs de comparaison avec une borne incluse ou exclue.
Un cas limite à la note 90 vérifie si la règle de la note A utilise la comparaison inclusive requise.
Chaîne d’appels
Une chaîne d’appels est la suite des appels de fonctions actifs qui ont conduit à l’opération courante, de l’appelant externe à l’appel le plus récent.
Une chaîne d’appels allant d’une fonction report à une fonction average montre comment une liste est parvenue à la fonction qui a divisé par sa longueur.
Chemin de recherche des modules
Le chemin de recherche des modules est la liste ordonnée des dossiers de sys.path que Python examine après ses modules intégrés lorsqu’il recherche des importations.
Un fichier auxiliaire hors du chemin de recherche des modules peut provoquer ModuleNotFoundError lorsque le script l’importe.
Code de premier niveau
Le code de premier niveau est constitué des instructions au niveau du module, hors des corps de fonctions, qui s’exécutent dans l’ordre au premier chargement du module.
Du code de premier niveau qui appelle print peut produire un affichage pendant l’importation même lorsque le programme qui importe n’appelle aucune fonction.

D

Débogage
Le débogage consiste à reproduire un comportement inattendu, à en localiser la cause, à la corriger et à vérifier à nouveau le comportement concerné.
Déboguer une boucle qui totalise des prix consiste notamment à observer les indices qu’elle parcourt avant de modifier sa valeur de départ.
Débogage par affichage
Le débogage par affichage ajoute des affichages temporaires à des endroits choisis du code pour révéler les valeurs, l’ordre d’exécution et vérifier si une hypothèse correspond au comportement.
Le débogage par affichage avec print(f"{i=} {total=}") identifie l’indice de boucle et le total au moment examiné.
Débogueur
Un débogueur met l’exécution d’un programme en pause et fournit des commandes pour examiner les valeurs courantes et avancer dans le code étape par étape.
Un débogueur te permet d’entrer dans calculate pour examiner ses arguments lorsque l’appelant reçoit une réponse incorrecte.
Découverte des tests
La découverte des tests trouve les tests exécutables à l’aide de règles de nommage des fichiers et des méthodes, comme le motif de fichier test*.py par défaut de unittest.
La découverte des tests avec python -m unittest peut exécuter les fichiers correspondants sans les lister individuellement dans une commande.
Distribution
Une distribution est un projet Python installable, identifié par un nom pour le gestionnaire de paquets, qui peut différer du nom utilisé dans les importations.
La distribution beautifulsoup4 s’installe sous ce nom, mais sa documentation indique aux utilisateurs Python d’importer bs4.
Diviser pour régner
La méthode diviser pour régner réduit la zone de recherche d’un débogage en vérifiant les valeurs intermédiaires nécessaires et en suivant la partie où elles deviennent incorrectes.
La méthode diviser pour régner dirige l’attention vers la conversion si les données brutes sont correctes mais que les valeurs converties sont déjà incorrectes.
Docstring
Une docstring est une chaîne placée au début d’un module ou d’une fonction, qui en documente le rôle et peut être affichée avec help().
Une docstring de circle_area peut expliquer l’argument du rayon et l’aire renvoyée à l’appelant.

E

Erreur d’exécution
Une erreur d’exécution est un problème détecté pendant l’exécution du code, comme une opération invalide qui lève une exception à ce moment.
Une erreur d’exécution se produit lorsqu’une expression de division valide est atteinte avec un diviseur dont la valeur est zéro.
Erreur de logique
Une erreur de logique provoque un comportement incorrect du programme alors que ses instructions s’exécutent sans produire de rapport d’exception.
Une erreur de logique dans une boucle qui commence à l’indice 1 ignore le premier prix et donne un total trop faible.
Erreur de syntaxe
Une erreur de syntaxe signifie que le code ne respecte pas la grammaire de Python, par exemple à cause de deux-points manquants, et empêche le script concerné de démarrer normalement.
Une erreur de syntaxe après if ready peut être corrigée en ajoutant les deux-points requis avant son bloc indenté.
Erreur de test
Une erreur de test est un résultat de test causé par une exception inattendue autre qu’une assertion qui a échoué, dans le test ou le code qu’il appelle.
Une erreur de test marquée E peut se produire lorsqu’une fonction lève TypeError avant que la vérification d’égalité reçoive une valeur.
Exception
Une exception signale un problème détecté pendant l’exécution ; une exception non gérée arrête le programme et produit normalement une trace d’appels.
Une exception due à une division par zéro peut arrêter average avant que son appelant affiche la moyenne calculée.
Exemple minimal reproductible
Un exemple minimal reproductible est constitué du plus petit code et de la plus petite entrée qui conservent un échec, afin que les étapes pertinentes puissent être examinées directement.
Un exemple minimal reproductible peut réduire des centaines d’enregistrements aux deux qui déclenchent encore le même échec.

É

Échec de test
Un échec de test est un résultat de test causé par une assertion fausse, par exemple lorsque la valeur de retour obtenue diffère de la valeur attendue indiquée dans la spécification.
Un échec de test marqué F peut montrer que la fonction a renvoyé "B" là où la règle vérifiée exigeait "A".

G

Garde du programme principal
Une garde du programme principal est un bloc if __name__ == "__main__": dont le corps s’exécute lors d’une exécution directe et est ignoré lors d’une importation ordinaire.
Une garde du programme principal autour de main() permet aux tests d’importer les fonctions du module sans lancer son application.
Graine
Une graine initialise un générateur pseudo-aléatoire et permet de reproduire sa séquence pour les mêmes appels avec la même version de Python.
Définir la graine avant une simulation permet à un programmeur d’examiner à nouveau la même séquence pendant le débogage.

H

Hypothèse
Une hypothèse est une explication précise proposée pour un bug, qui prédit une observation vérifiable dans le programme en cours d’exécution.
L’hypothèse selon laquelle une boucle ignore son premier élément prédit qu’un affichage de ses indices ne montrera jamais 0.

I

Importation générique
Une importation générique utilise * pour introduire les noms publics d’un module dans le programme courant, ce qui peut masquer leurs origines et remplacer des liaisons existantes.
L’importation générique from math import * peut remplacer une variable appelée e par la constante mathématique.
ImportError
Une ImportError peut se produire lorsque from demande un nom indisponible dans un module, même si Python a trouvé le module lui-même.
Une ImportError provoquée par from math import square_root indique un problème avec le nom demandé, pas une installation absente.
IndexError
Une IndexError se produit lorsqu’un accès à une séquence demande une position qui n’existe pas, comme l’indice 3 dans une liste à trois éléments.
Une IndexError provoquée par names[4] invite à vérifier la longueur de la liste et les bornes de la boucle qui a produit 4.
Interpréteur
Un interpréteur est le programme qui exécute le code Python ; différents interpréteurs installés peuvent disposer de paquets tiers différents.
Le choix de l’interpréteur de l’éditeur explique pourquoi un paquet installé pour un autre Python peut encore manquer.

K

KeyError
Une KeyError se produit lorsqu’un accès à un dictionnaire demande une clé absente : Python ne peut donc pas renvoyer de valeur pour cette clé par indexation.
Une KeyError pour "price" peut révéler que le dictionnaire courant n’a jamais reçu l’entrée de prix attendue.

M

Masquage de module
Le masquage de module se produit lorsqu’un module trouvé plus tôt porte le nom du module recherché et le masque pendant la recherche d’importation.
Le masquage de module par un fichier local random.py peut priver un script de la fonction randint de la bibliothèque.
Méthode de test
Une méthode de test est une fonction dans une classe de test dont le nom commence par test, ce qui permet à unittest de découvrir et d’exécuter ses vérifications.
Une méthode de test nommée test_limit peut vérifier une limite séparément du test d’une entrée ordinaire.
Module
Un module est une unité de code Python, généralement un fichier .py, dont les fonctions et les variables peuvent être importées pour être utilisées dans un autre programme.
Le module math fournit sqrt : un programme peut donc calculer des racines carrées sans définir cette fonction.

N

NameError
Une NameError se produit lorsque Python ne trouve pas de liaison pour un nom utilisé dans une expression, souvent à cause d’une faute de frappe ou d’une importation manquante.
Une NameError pour sqrt après le seul import math signifie que la fonction nécessite ici le préfixe math..
Nombre pseudo-aléatoire
Un nombre pseudo-aléatoire est produit par un algorithme déterministe dont la séquence est conçue pour sembler aléatoire dans des usages comme les simulations.
Un nombre pseudo-aléatoire obtenu avec random.randint(1, 6) peut représenter le résultat d’un dé dans la simulation d’un jeu de société.
Notation pointée
La notation pointée permet d’accéder à un attribut nommé dans un objet ou un module en plaçant un point entre le nom de l’objet et celui de l’attribut.
La notation pointée dans math.sqrt(25) trouve la fonction sqrt dans le module math déjà importé.

O

Opération en place
Une opération en place modifie un objet existant, comme une liste, sans nécessiter un nouvel objet pour contenir les éléments modifiés.
L’opération en place random.shuffle(cards) modifie cards et renvoie None : elle ne nécessite donc pas d’affectation.
Option d’optimisation
L’option d’optimisation -O modifie l’exécution de Python en supprimant les instructions assert : une validation requise ne peut donc pas reposer sur ces instructions.
Lancer un script avec l’option d’optimisation fait disparaître une vérification d’âge négatif fondée uniquement sur une assertion.

P

Paquet
Un paquet regroupe des modules Python apparentés, généralement dans un dossier, afin que les programmes puissent organiser et réutiliser un ensemble plus vaste de code.
Un paquet tiers peut fournir plusieurs modules apparentés qu’un programme importe pour différentes tâches.
Partie entière
La partie entière d’un nombre est le plus grand entier inférieur ou égal à ce nombre ; math.floor va vers l’infini négatif lorsque c’est nécessaire.
La partie entière de -3,2 est -4 : math.floor(-3.2) diffère donc de la conversion avec int(-3.2).
Partie entière supérieure
La partie entière supérieure d’un nombre est le plus petit entier supérieur ou égal à ce nombre ; math.ceil effectue cet arrondi à l’entier supérieur.
Un calcul de partie entière supérieure transforme 3,4 pots de peinture nécessaires en quatre pots entiers, suffisants pour la surface indiquée.
Pas à pas détaillé
Le pas à pas détaillé est une action du débogueur qui entre dans une fonction appelée sur la ligne courante, afin que tu puisses examiner les étapes à l’intérieur de cette fonction.
Utilise le pas à pas détaillé sur result = convert(text) lorsque la valeur renvoyée est incorrecte et que le texte d’entrée semble correct.
Pas à pas principal
Le pas à pas principal est une action du débogueur qui exécute la ligne courante, y compris les fonctions appelées, sans suivre leurs lignes internes.
Utilise le pas à pas principal sur un appel de calcul lorsque tu veux examiner son résultat renvoyé dans l’appelant.
pip
pip est un outil d’installation qui télécharge et gère des distributions Python tierces pour l’interpréteur qui l’exécute.
Exécuter python3 -m pip show cowsay demande au pip associé à python3 d’afficher les détails d’installation de ce paquet.
Point d’arrêt
Un point d’arrêt marque un endroit où un débogueur met l’exécution en pause, ce qui permet de l’examiner avant de poursuivre avec le code suivant.
Un point d’arrêt avant une mise à jour de boucle permet de comparer le total courant à l’élément qui va être ajouté.
PyPI
PyPI est le Python Package Index, un dépôt public où les éditeurs rendent des distributions tierces disponibles à l’installation.
La page PyPI d’un paquet fournit des informations sur le projet et une documentation à consulter avant son installation.

R

Régression
Une régression est un bug introduit dans un comportement qui fonctionnait auparavant, souvent après une modification du code dont dépendent d’autres fonctions ou tests.
Une régression peut faire échouer un total à un élément qui réussissait auparavant après une modification destinée à corriger une entrée vide.

S

Spécification
Une spécification énonce le comportement qu’une fonction doit assurer et fournit une base indépendante pour les entrées, les résultats attendus et les vérifications valides des tests.
La spécification selon laquelle les notes d’au moins 90 obtiennent un A fixe la réponse attendue pour un test à exactement 90.

T

Tableau de suivi
Un tableau de suivi consigne les valeurs des variables aux étapes successives de l’exécution, ce qui permet de suivre un programme à la main et d’examiner ses changements.
Un tableau de suivi d’une boucle d’accumulation montre le total avant et après l’ajout de chaque élément.
Test unitaire
Un test unitaire est une petite vérification automatisée d’une unité comme une fonction, qui compare son comportement pour une entrée choisie à un résultat attendu.
Un test unitaire vérifie qu’une fonction de prix renvoie 0 pour une liste vide lorsque sa spécification exige ce résultat.
TestCase
Un TestCase est la classe de base de unittest pour les classes de test ; il fournit des méthodes d’assertion et permet l’exécution de chaque test découvert.
Une classe qui hérite de unittest.TestCase peut appeler self.assertEqual dans ses méthodes de test nommées.
Tirage sans remise
Un tirage sans remise choisit des positions différentes dans l’entrée : chaque position est donc sélectionnée au plus une fois, même si des valeurs se répètent.
Un tirage sans remise dans ["A", "A", "B"] peut sélectionner les deux positions qui contiennent "A".
Trace d’appels
Une trace d’appels présente la chaîne des appels actifs lors d’une exception non gérée et se termine par le type d’exception et son message.
Lis d’abord la dernière ligne de la trace d’appels, puis remonte du cadre qui a échoué vers l’appel d’origine.
TypeError
Une TypeError signale un type inadapté à une opération ou un nombre incorrect d’arguments dans un appel de fonction, par exemple un argument obligatoire manquant.
Une TypeError provoquée par "Score: " + 8 indique qu’une chaîne et un entier ne peuvent pas être assemblés par cette expression.
Typosquatting
Le typosquatting consiste à publier sous un nom ressemblant à celui d’un projet de confiance pour piéger les personnes qui saisissent mal son nom lors de l’installation d’un logiciel.
Vérifier l’orthographe exacte d’un projet sur PyPI aide à éviter le typosquatting lors de la copie d’une commande d’installation.

V

Validation des entrées
La validation des entrées vérifie si les données externes respectent les exigences d’un programme et réagit aux entrées inadaptées avant de les utiliser.
La validation des entrées avec if score < 0 reste active lorsque Python s’exécute sans les assertions.
ValueError
Une ValueError signale qu’une opération accepte le type de l’entrée mais ne peut pas utiliser sa valeur particulière, par exemple un texte numérique invalide.
Une ValueError provoquée par int("6.2") signifie que la chaîne ne décrit pas un entier sous la forme requise.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer