Passer au contenu

Fondamentaux de la programmation

Informatique universitaire · Sujet 1

1.1

Ce que ce cours est, et comment l'utiliser

Ceci est le premier cours d'informatique à l'université : fondamentaux de la programmation , enseigné avec Python 3. Il ne suppose aucune connaissance préalable en programmation. Chaque programme de ce document est complet et exécutable — saisissez-le, exécutez-le, modifiez une seule ligne, et prévoyez ce qui changera avant de relancer l'exécution. Cette boucle prévoir-ensuite-exécuter constitue la compétence entière.

Le cours est une échelle :

  • Les unités 1.1 à 1.3 construisent les mécanismes : valeurs et types, sélection, itération.
  • L'unité 1.4 encapsule le travail en fonctions.
  • Les unités 1.5 et 1.6 ajoutent les collections standards et les fichiers avec gestion des erreurs.
  • L'unité 1.7 représente la discipline supérieure : décomposition des problèmes, tests, débogage.

Comment lire chaque unité : une courte histoire explique pourquoi c’est important ; une image ou un principe général viennent avant toute syntaxe ; puis les règles précises ; ensuite des exemples corrigés qui deviennent progressivement plus difficiles, chacun avec une trace que vous pouvez vérifier en exécutant le code ; puis les erreurs réelles que les gens commettent ; puis un résumé de trois lignes. Chaque exemple ici peut être vérifié d’une seconde manière — en l’exécutant. Lire du code sans l’exécuter, c’est comme lire une partition musicale sans l’entendre.

Vocabulaire Entrainer
English Français
programming fundamentals/ˈprəʊɡræmɪŋ ˌfʌndəˈmentlz/ fondamentaux de la programmation
type/taɪp/ type
1.1

Valeurs, types et entrée/sortie

Une application de shopping affiche "4.20" — s’agit-il de texte ou d’un nombre ? Si c’est du texte, ajouter deux les prix donnent "4.203.50" ; si c'est un nombre, il donne 8.7. Lequel se produit est décidé selon le type, et l'ensemble de l'unité 1.1 consiste à apprendre à identifier les types avant même d'exécuter quoi que ce soit. exécuter quoi que ce soit.

Une valeur possède un type, et le type détermine ce que vous pouvez en faire : int (nombre entier, nombres), float (décimaux), str (texte), bool (True/False). La type(...) elle ne modifie jamais l’ancienne valeur. L’image mentale, à conserver pour tout le cursus :

age = 21              # int
price = 4.20          # float
name = "Ada"          # str
open_ = True          # bool
print(type(age))      # <class 'int'>

Variables sont des noms liés à des valeurs ; l'affectation age = 22 lie le nom à nouveau — elle ne modifie jamais la valeur précédente. L'image mentale, utile tout au long de la formation :

État du programme sous forme de boîtes : chaque étiquette de nom pointe vers sa propre boîte de valeur ; la réaffectation déplace l'étiquette, jamais la boîte. L'expression 6 * 3.50 lit deux boîtes et produit une nouvelle boîte flottante 21.0
Les noms sont des étiquettes sur des boîtes ; les expressions lisent les boîtes et créent de nouvelles boîtes

marque un nombre à virgule flottante, car count * 3.50 promeut le résultat vers un float. Surveiller quel type sort avec count = 6 ouvre la boîte int 6 et la boîte float 3.50, et la règle de mélange de Python promeut la int — le résultat est la float 21.0, jamais la int 21.

La conversion est explicite : int("21") est 21, mais "4" + 2 est un TypeError — Python refuse de deviner si vous vouliez dire "42" ou 6. Utilisez print(...) pour la sortie ; entrez avec input(...), qui retourne toujours une chaîne, donc les nombres nécessitent une conversion :

born = int(input("Birth year? "))
print("About", 2026 - born, "years old")

Exemple résolu 1 (la caisse du café). count = int(input("Coffees? ")), puis print("Total:", count * 3.50). À 6 cafés, cela affiche Total: 21.0 — le .0 ajoutez un int * float à l'intérieur de la boucle et laissez Python vous évaluer. d'une expression est l'habitude même d'unité 1.1. Tracez-le à l'état : input retourne la chaîne "6" ; int(...) ouvre une nouvelle boîte contenant le int 6 ; la multiplication crée une nouvelle boîte float 21.0 ; print l'affiche.

Exemple résolu 2 (l'accident classique, réparé). Un imprimeur de bannières ajoute un compteur à un message :

count = int(input("Tickets? "))
print("Sold " + count + " today")

Lancez-le et Python élève TypeError: can only concatenate str (not "int") to str — la règle refuse de deviner. La réparation nomme explicitement la conversion : print("Sold " + str(count) + " today"), ou la version plus propre print("Vendu", count, "aujourd'hui"), which inserts the spaces for you. The lesson to carry: + signifie addition pour les nombres, concaténation pour les chaînes, jamais un mélange silencieux.

Erreurs courantes. Oublier que input() donne toujours une chaîne, donc input() * 2 répète le texte plutôt que de doubler un nombre. Écrire 4.20 + 6 et s'attendre à une réponse int — n'importe quel float dans l'expression produit un float. Se fier à 0.1 + 0.2 == 0.3 (c'est False ; arrondi binaire — unité 1.2 montre la correction).

Résumé : quatre types de base déterminent chaque opération ; les noms sont des étiquettes, l'affectation réattribue la liaison; les expressions mélangent les types par promotion avec des flottants ; les conversions sont explicites et input() en nécessite une.

Vocabulaire Entrainer
English Français
value/ˈvæljuː/ valeur
variables/ˈveərɪəblz/ variables
set/set/ ensemble
1.2

Sélection : choisir entre plusieurs chemins

Un tourniquet de parc à thème doit facturer différemment les enfants, les adultes et les personnes âgées — un seul programme, plusieurs chemins. La sélection est le moyen par lequel un programme choisit : if, elif, else exécute un bloc uniquement si une condition est satisfaite.

Diagramme de flux des règles de prix du cinéma avec la vérification d'âge avant la vérification d'étudiant ; un étudiant de 70 ans prend la première branche vraie et paie 5
Âge 70, étudiant : la première branche vraie détermine le prix

La condition est n'importe quelle expression booléenne ; les comparaisons (==, !=, <, >=) et la logique (and, or, not) la construisent. Deux règles rendent toute décision lisible :

  1. Les branches sont testées de haut en bas ; la première branche vraie l'emporte et le reste est ignoré.
  2. L'indentation n'est pas décorative — elle DÉFINIT le bloc. Un espace supplémentaire change quelles lignes appartiennent à la branche.
temp = 37.5
if temp >= 38:
    print("Fever")
elif temp >= 36 and temp < 38:
    print("Normal")
else:
    print("Low")

Exemple corrigé 1 (le prix du cinéma). Sous 12 ou 65+ payez 5, les étudiants paient 7, tous les autres paient 10 :

age = int(input("Age? "))
student = input("Student? y/n ") == "y"
if age < 12 or age >= 65:
    price = 5
elif student:
    price = 7
else:
    price = 10
print("Pay", price)

L'ordre compte : la première branche vraie gagne, c'est pourquoi la vérification de l'âge précède celle student check — a 70-year-old student should pay 5, and this ordering says so. Run it with 70 and y to see the flowchart's leftmost path taken.

Exemple corrigé 2 (tranches de notes, évolutif). Même squelette, maintenant avec une chaîne où chaque elif ne nécessite qu'une seule comparaison, car les tests situés au-dessus ont déjà échoué :

score = int(input("Score? "))
if score >= 80:
    band = "A"
elif score >= 70:
    band = "B"
elif score >= 60:
    band = "C"
else:
    band = "F"
print("Band:", band)

À 79, le premier test échoue et le second réussit : Band: B. L'escalade vers remarquer que la condition elif score >= 70 n'a pas non plus besoin de and score < 80 — atteindre cette ligne prouve déjà que la note est inférieure à 80. Compter sur l'exécution séquentielle ainsi est ce qui rend les chaînes courtes ; ré tester tout est la version plus longue et erronée du débutant. version.

Floating-point comparisons need care: 0.1 + 0.2 == 0.3 is False (binary rounding), so compare against a tolerance: abs(x - y) < 1e-9.

Erreurs fréquentes. Écrire = là où on entendait == — le bug classique, et Python le refuse dans les conditions (SyntaxError) précisément parce qu'il est si courant. Tester le cas particulier après le cas général, afin que le cas général remporte toujours la victoire. Utiliser elif avec une condition qui ne peut jamais être atteinte car une branche antérieure l'a déjà capturée.

Résumé : les conditions choisissent les chemins, le premier vrai gagne, l'indentation définit le bloc ; ordonner les tests du spécifique au général ; les nombres à virgule se comparent par tolérance, jamais par ==.

1.3

Itération : refaire encore

Payer des factures 5,000 à la main est une carrière ; avec une boucle, c'est un programme. Itération répète un travail : une boucle for parcourt une séquence connue ; une boucle while s'exécute tant qu'une condition reste vraie. La question de conception est toujours : connaissez-vous le nombre de passages, ou doit-on une condition?

total = 0
for i in range(1, 101):      # 1..100 — range stops BEFORE its end
    total += i
print(total)                  # 5050

Utilisez for lorsque le nombre de passages est connu ; utilisez while lorsque c'est une condition qui décide. Chaque while nécessite trois éléments visibles dans le code : l'initialisation de la variable, la condition, et une modification à l'intérieur qui tend vers la sortie — sinon il s'agit d'une boucle infinie. tableau de traçage pour la boucle factorielle*

La boucle while factorielle à côté de sa table de traçage : n et factorial après chaque tour, de 5 et 1 à 1 et 120, lorsque la condition devient Fausse Le tableau de traçage est l'habitude de vérification du cours pour les boucles : suivez les variables

n = 5
factorial = 1
while n > 1:
    factorial *= n
    n -= 1                    # the step toward exiting
print(factorial)              # 120

tour par tour, d'abord sur papier. Pour la boucle factorielle : variables round by round, on paper first. For the factorial loop: ajoutez un (n=5, f=1) → (4, 5) → (3, 20) → (2, 60) → (1, 120) à l'intérieur de la boucle et laissez Python vous évaluer. add a print(n, factorial) inside the loop and let Python grade you.

2 supérieur à break — le compteur de passages est inconnu, la condition décide : 7 qui est supérieur à 100 — le nombre de tours est inconnu, la condition décide :

n = 100
while True:
    if n % 7 == 0:
        break                 # found it — leave the loop now
    n += 1
print(n)                      # 105

La trace est courte : 100, 101, …, 104 échouent tous au test ; 105 réussit et break sort. break quitte la boucle précocement ; continue passe à l'itération suivante. Les deux sont outils de lisibilité — une boucle qui doit parcourir jusqu'à trouver quelque chose, puis s'arrêter, lit faut-il à break pour atteindre 5 ? que fait 1000 pour atteindre 2000 ?

balance = 1000.0
years = 0
while balance < 2000.0:       # the condition itself is the goal
    balance *= 1.05
    years += 1
print(years, round(balance, 2))   # 15 2078.93

Quinze ans, et la boucle s'arrête dès que la condition bascule — le tableau de trace montrerait le solde franchissant la ligne à 2078.93, sans atterrir exactement sur 2000.

Erreurs courantes. Modifier la liste (unité 1.5) ou la variable de boucle que vous êtes for-boucle sur. range(1, 100) lorsque 100 était prévu — la fin est exclue. Une while dont l'étape de sortie est absente ou commentée : la condition ne bascule jamais, et le programme se bloque.

Résumé : for pour les comptages d'itérations connus, while pour les conditions ; chaque boucle affiche le début, la condition et l'étape ; traçage sur papier, puis impression au niveau du grade ; break et continue pour les sorties précoces propres.

Vocabulaire Entrainer
English Français
list/lɪst/ liste
dictionary/ˈdɪkʃənəri/ dictionnaire
1.4

Fonctions : nommer une tâche une seule fois

Le même calcul de prix apparaît à cinq endroits ; la règle fiscale change ; quatre des cinq sont mis à jour. Une fonction encapsule une tâche derrière un nom afin qu'elle soit écrite une seule fois et fiable partout : des paramètres en entrée, une valeur de retour en sortie. def définit ; l'appel exécute.

def total_price(count, unit=3.50):
    """Return the total for count items at unit price."""
    return count * unit

print(total_price(6))            # 21.0
print(total_price(6, unit=4.0))  # 24.0

La définition fournit un paramètre (count, unit) ; l'appel fournit un argument (6). Une valeur par défaut (unit=3.50) rend un argument optionnel. return renvoie une valeur et termine l'appel ; l'affichage n'est pas un retour — une fonction sans return retourne None, et l'appelant qui tente une arithmétique dessus obtient une erreur de TypeError.

Trois cadres d'appel : print appelle order_total(250, 4), ce qui s'interrompt pendant que add_fee(1000) s'exécute ; 1003 est retourné tout au long de la chaîne
Appels imbriqués : l'appelant s'interrompt jusqu'à ce que la valeur revienne

Chaque appel possède sa propre portée locale : les noms à l'intérieur sont invisibles à l'extérieur, et disparaissent lorsque l'appel se termine. Un trace d'appels imbriqués s'affiche : appelant en pause → destinataire s'exécute → valeur de retour atterrit chez l'appelant.

Exemple résolu 1 (la commande incluant les frais).

def add_fee(amount):
    """Return amount plus a fixed 3 pence fee."""
    return amount + 3

def order_total(unit_pence, quantity):
    """Return the order total: subtotal plus the fixed fee."""
    return add_fee(unit_pence * quantity)

print(order_total(250, 4))   # 1003

Le contrat dans le docstring est crucial : pence entiers entrants, pence entiers sortants. Tracé order_total(250, 4) : sous-total 1000, add_fee retourne 1003 — et la frame diagramme ci-dessus montre la pause et la restitution.

Exemple résolu 2 (un algorithme réel à l'intérieur d'une petite fonction, amplifié). is_prime(n) retourne True lorsque rien de 2 jusqu'à $\sqrt{n}$ ne divise n :

def is_prime(n):
    if n < 2:
        return False
    d = 2
    while d * d <= n:        # only test up to the square root
        if n % d == 0:
            return False     # found a divisor — answer known, stop
        d += 1
    return True

print([p for p in range(2, 30) if is_prime(p)])
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Deux habitudes de fonction se rencontrent ici : un premier return termine l'appel dès que la réponse est connue (pas besoin de variable flag), et la limite de boucle d * d <= n provient de la dérivation — si $n = a \times b$ avec $a \le b$, alors $a \le \sqrt{n}$, donc tester au-delà de $\sqrt{n}$ ré-teste des diviseurs déjà vus. Exécution : la liste correspond exactement aux nombres premiers inférieurs à 30.

Erreurs courantes. Imprimer à l'intérieur d'une fonction au lieu de retourner, de sorte que le résultat ne peut pas être réutilisé. Oublier le return sur une branche — ce chemin produit silencieusement None. Accéder aux variables locales d'une fonction depuis l'extérieur ; elles disparaissent lorsque l'appel se termine.

Résumé : def une seule fois, appel n'importe où ; paramètres entrants, une seule valeur sortante via return; retours précoces terminent l'appel ; les variables locales naissent et meurent avec l'appel ; les docstrings énoncent le contrat.

Vocabulaire Entrainer
English Français
string/strɪŋ/ chaîne de caractères
selection/sɪˈlekʃn/ sélection
iteration/ˌɪtəˈreɪʃn/ itération
infinite loop/ˈɪnfɪnət luːp/ boucle infinie
trace table/treɪs ˈteɪbl/ tableau de traçage
function/ˈfʌŋkʃn/ fonction
return value/rɪˈtɜːn ˈvæljuː/ valeur de retour
parameter/pəˈræmɪtə/ paramètre
argument/ˈɑːɡjuːmənt/ argument réel
local scope/ˈləʊkl skəʊp/ portée locale
1.5

Collections : listes, dictionnaires, tuples, ensembles

La caisse d'un café a besoin des commandes de la journée par ordre, du menu par nom, d'une localisation qui ne doivent pas dériver, et les boissons uniques de la journée. Quatre jobs, quatre conteneurs — le choix parmi eux est la décision de conception de l'unité 1.5.

Une liste est une séquence ordonnée et modifiable : marks = [72, 85, 61], indexée à partir de 0, découpée avec marks[1:3]. Un dictionnaire fait correspondre des clés à des valeurs : price = {"flat white": 3.5, "tea": 2.8}, lu et écrit par clé. Un tuple est une séquence fixe (53.1, -1.5) — idéal pour les coordonnées qui ne doivent pas changer. Une ensemble contient des éléments uniques sans ordre : {"a", "b"}.

marks = [72, 85, 61]
marks.append(90)               # [72, 85, 61, 90]
best = max(marks)              # 90
average = sum(marks) / len(marks)   # 77.0
Les noms a et b pointent tous deux vers un même objet liste, contenant 1 et 2 après b.append(2)
Aliasing : deux noms, une liste

L'affectation ne copie jamais : a = [1]; b = a; b.append(2) rend a [1, 2] — la liste est partagée, les noms ne le sont pas. Cet aliasing représente encore les boîtes de l'unité 1.1, maintenant avec deux étiquettes sur une seule boîte, et cela explique aussi la règle suivante : modifier une liste tout en itérant dessus saute des éléments — itérez sur une copie (for m in marks[:]) ou construisez une nouvelle liste.

Exemple résolu 1 (dénombrement par catégorie).

orders = ["tea", "flat white", "tea", "tea", "mocha"]
tally = {}
for item in orders:
    tally[item] = tally.get(item, 0) + 1
print(tally)   # {'tea': 3, 'flat white': 1, 'mocha': 1}

La méthode .get(key, 0) du dictionnaire fournit 0 pour une première observation — l'idiome qui rend le comptage en une seule ligne. Vérifiez manuellement : "tea" apparaît trois fois dans orders, et le dénombrement affiché le confirme.

Exemple résolu 2 (le meilleur vendeur de la journée, amplifié). En s'appuyant sur le dénombrement, rapportez l'article le plus populaire et son nombre :

best = max(tally, key=tally.get)
print(best, tally[best])       # tea 3

L'argument key=tally.get demande à max de comparer des éléments selon leurs comptes plutôt que alphabétiquement — la même astuce key= classe n'importe quelle collection selon n'importe quel critère. Le chaînage est essentiel : les programmes réels enchaînent ces outils (compte, puis classement) plutôt que de re-parcourir orders deux fois.

Choisir le conteneur est une décision de conception : ordre + doublons → liste ; recherche par nom → dictionnaire ; groupements fixes → tuple ; unicité → ensemble.

Erreurs courantes. Accéder à tally[item] += 1 sur une clé qui n'est pas encore dans le dictionnaire (KeyError) — .get est la solution. S'attendre à ce qu'un ensemble ou un dictionnaire mémorise l'ordre. Supposer que b = a copie une liste ; il crée une alias vers celle-ci.

Résumé : quatre conteneurs pour quatre tâches ; l'affectation partage, jamais ne copie ; .get rend le comptage sûr ; key= transforme le classement en une seule ligne.

Vocabulaire Entrainer
English Français
tuple/ˈtuːpl/ tuple
aliasing/ˈeɪlɪəsɪŋ/ aliasage
1.6

Fichiers et erreurs

Le café ferme, le courant tombe — et le total du matin ne survit que si le programme l'a écrit sur disque. Un fichier persiste au-delà du programme. with open(path) as f: opens, closes on exit, and reads text; open(path, "w") écrit (et vide d'abord — l'accident classique).

with open("log.txt", "w") as f:
    f.write("opened\n")

with open("log.txt") as f:
    for line in f:
        print(line.rstrip())     # rstrip removes the trailing newline

Le bloc with est la barrière de sécurité : quoi qu'il arrive à l'intérieur, le fichier se ferme. La lecture renvoie des lignes avec leur retour à la ligne, donc .rstrip() appartient à chaque boucle.

Les erreurs sont des valeurs que Python lève comme exceptions : FileNotFoundError, ValueError, KeyError, TypeError. try/except intercepte un type nommé — jamais un vide except: qui cache de vrais bugs.

Exemple résolu 1 (fichier de configuration absent). Lire une taille depuis un fichier de paramètres qui peut être manquant, ou ne pas contenir un nombre entier :

try:
    with open("settings.txt") as f:
        size = int(f.read().strip())
except FileNotFoundError:
    size = 12                    # no file yet: a sensible default
except ValueError:
    size = 12                    # the file holds "big", not a number
print("Text size", size)

L'exécuter trois fois — avec 16 dans le fichier, sans fichier, et avec big dans le fichier — et il affiche une taille exploitable à chaque fois, par trois chemins différents. C'est là la forme du code robuste : une approche sensée plusieurs voies y menant. Gérer l'erreur que vous prévoyez, là où vous pouvez répondre à elle ; laisser les autres s'afficher bruyamment.

Un lecteur de paramètres : le bloc try ouvre, lit et convertit la valeur ; soit ça fonctionne, soit une branche FileNotFoundError ou ValueError définit la taille par défaut 12 ; les trois voies se rejoignent et le programme continue

**Exemple résolu 2 (une boucle d'entrée robuste, escalated). Demander jusqu'à ce que l'utilisateur tape un nombre entier :

def read_count():
    while True:
        try:
            return int(input("How many? "))
        except ValueError:
            print("Whole numbers only.")

print(read_count())

Alimenter avec x puis 4 : le premier passage lève une exception, est capturé, affiche le message, et le while True demande à nouveau ; le second passage réussit avec int(...) et return sort de la boucle et de la fonction en un seul geste. Trois unités se combinent ici — la boucle (1.3), le contrat de fonction (1.4) et l'exception (1.6) — ce qui constitue le point de l' escalade.

Erreurs courantes. ⟨open(path, "w")⟩ sur le mauvais chemin : le fichier est créé ou vidé avant que vous ne vous en rendiez compte. Capturer ⟨Exception⟩ de manière large et continuer avec un état corrompu. Oublier ⟨.rstrip()⟩, ce qui fait apparaître des lignes doublement espacées dans la sortie.

Résumé : ⟨with open(...)⟩ pour la lecture et l'écriture ; ⟨"w"⟩ vide d'abord ; les exceptions sont des valeurs — capturez le type nommé que vous attendez, réagissez de manière sensée, laissez les autres s'afficher.

Vocabulaire Entrainer
English Français
file/faɪl/ fichier
exceptions exceptions
decomposition/ˌdiːkɒmpəˈzɪʃn/ décomposition
testing/ˈtestɪŋ/ test
debugging/ˈdiːbʌɡɪŋ/ débogage
1.7

Décomposition, tests et débogage

Deux équipes écrivent la même application ; l'une la livre en une semaine, l'autre s'enfonce pendant un mois. La différence ne tient pas à la vitesse de frappe — c'est que le code de l'équipe rapide est construit à partir de petits morceaux dont chacun peut être prouvé correct individuellement, tandis que l'équipe lente déborde une application entière d'un coup. L'Unit 1.7 est cette discipline.

La décomposition divise un problème en fonctions d'une seule tâche chacune — chaque morceau est assez petit pour être testé seul. Le test compare la sortie réelle d'une fonction avec celle attendue, aux limites : zéro, un, vide, négatif, immense.

La boucle pilotée par les tests : écrire un test défaillant qui énonce le contrat ; l'exécuter et voir échouer pour la bonne raison ; écrire le corps le plus simple qui passe ; ré-exécuter jusqu'à ce qu'il soit vert ; refactoriser en gardant les tests comme structure
La boucle pilotée par les tests : rouge, vert, refactor
def add_fee(amount):
    return amount + 3

def order_total(unit_pence, quantity):
    return add_fee(unit_pence * quantity)

assert order_total(250, 4) == 1003
assert order_total(250, 0) == 3      # the zero-quantity boundary
assert order_total(0, 4) == 3

Un assert assert qui ne se déclenche jamais est un test passant. Écrire les tests avant le code lorsque possible — ils constituent le contrat exécuté, et la boucle ci-dessus (rouge → vert → refactor) est cette habitude en action continue. (rouge → vert → refactoring) c'est cette habitude en exécution continue.

1% sur £order_total — le test est écrit en premier, à la nouvelle limite : Vérifier manuellement le test du milieu : subtotal 10, dix pour cent de réduction donne 10, et

def order_total(unit_pence, quantity):
    subtotal = add_fee(unit_pence * quantity)
    if subtotal >= 1000:             # pence: over £10
        subtotal = int(subtotal * 0.9)
    return subtotal

assert order_total(200, 4) == 803    # under £10 — unchanged
assert order_total(250, 4) == 902    # 1003 pence → 10% off → 902.7 → 902
assert order_total(250, 5) == 1127   # 1253 pence → 1127.7 → 1127

Vérifiez le test central à la main : subtotal 1003, dix pour cent de réduction donne 902.7, et int(...) arrondit vers le bas à 902. Remarquez aussi le premier assert : à 200 pence et quatre tasses, le total reste 803 — les tests aux limites prouvent à la fois que la remise est appliquée et qu'elle ne s'active pas prématurément.

Exemple résolu 2 (bisecter un bug avec des prints, escaladé). Le décompte à partir de 1.5 imprime {'tea': 3} mais la ligne du best-seller imprime la mauvaise boisson. La méthode : (1) reproduire avec le plus petit cas échouant ; (2) afficher les valeurs à la limite entre la partie fiable et la partie suspecte — ici, le comptage avant l'impression max ; (3) corriger une chose ; (4) relancer les tests. Déplacer l'impression à mi-chemin du code à chaque exécution divise par deux la zone de recherche : quatre impressions permettent de trouver un bogue dans un programme de seize lignes, malgré sa capacité à se cacher.

Déboguer consiste à identifier l'écart entre ce que l'on pense que fait le code et ce qu'il fait réellement — l'impression au seuil de confiance/suspicion est l'outil.

Erreurs courantes. Tester uniquement le chemin heureux : les limites (zéro, un, vide, négatif) sont où les programmes plantent. Écrire une semaine de code avant le premier test, puis déboguer une montagne. Corriger deux choses à la fois, de sorte que ni l'un ni l'autre résultat ne soit d'un autre.

Summary : décomposer jusqu'à ce que chaque composant teste seul ; valider les limites dès qu'une fonction existe ; écrire le test en amont si possible ; déboguer par dichotomie avec des impressions aux seuils de confiance — l'habitude sur laquelle repose toute la formation universitaire.

Leçons interactives sur ce sujet

Traversez-le étape par étape, avec des exercices à vérification instantanée.

Plus de sujets dans Informatique universitaire

Se connecter ou créer un compte

IGCSE, A-Level & AP