Solutions — série 02-1 (if, elif, else : décider)
Rappel de la règle d'or : on n'ouvre ce fichier qu'après avoir terminé (ou sérieusement séché sur) la série. Compare le raisonnement, pas seulement le code : une solution différente qui marche est souvent valable.
Exercice facile a — positif, négatif ou nul
Raisonnement — Trois cas mutuellement exclusifs → UNE chaîne if/elif/else, pas trois if séparés (avec trois if, chaque condition serait testée même quand la réponse est déjà connue — inutile, et source de bugs dès que les conditions se recouvrent). Le cas nul ne nécessite aucune condition : si n n'est ni positif ni négatif, il est nul — c'est le else.
Solution
# ex-02-1-a.py
n = int(input("Un nombre entier ? ")) # int() : réflexe 01-2
if n > 0:
print("positif")
elif n < 0:
print("negatif")
else:
print("nul")
Sorties pour 7, -3, 0 : positif, negatif, nul.
Pourquoi ça marche — Les trois conditions couvrent tous les entiers sans recouvrement : Python descend la chaîne et s'arrête au premier bloc vrai. Le else attrape le seul cas restant (n == 0) sans avoir besoin de l'écrire — c'est exactement son métier.
Erreur classique sur cet exercice — Oublier int() : n reste une str, et "7" > 0 lève TypeError: '>' not supported between instances of 'str' and 'int' dès la première comparaison. Autre classique : écrire elif n == 0: puis un else avec un message d'erreur — pas faux, mais le troisième cas étant certain, le else direct est plus simple.
Variante plus difficile — Ajoute un quatrième message : petit positif pour 0 < n <= 10. Où doit-il se placer dans la chaîne pour ne jamais être masqué par positif ? (Avant lui : le premier bloc vrai gagne.)
Exercice facile b — prédire les comparaisons
Raisonnement — On applique deux règles de la leçon : == entre int et float compare les valeurs ; == entre str et autre chose répond False sans erreur ; et les textes sont comparés caractère par caractère, majuscules ≠ minuscules.
Solution
print(3 == 3.0) # True
print("3" == 3) # False
print(10 != 10) # False
print("a" == "A") # False
print(5 >= 5) # True
Pourquoi ça marche — 3 == 3.0 : Python compare les valeurs numériques, peu importe int/float. "3" == 3 : un texte n'est jamais égal à un nombre — silencieusement. 10 != 10 : « différent de » est faux quand c'est égal. "a" == "A" : Python distingue la casse (comme pour les noms de variables, leçon 01-1). 5 >= 5 : le « ou égal » rend la comparaison vraie.
Erreur classique sur cet exercice — Répondre True à "3" == 3 « parce que c'est le même chiffre ». Non : uniformes différents (01-2), jamais égaux, et c'est LE bug silencieux des input() non convertis.
Variante plus difficile — Prédis "b" > "a" puis vérifie. (Réponse : True — les chaînes se comparent par ordre alphabétique. Utile à savoir… et piégeux : ⏩ tu verras en 02-5 pourquoi comparer des NOMBRES restés en str produit des classements absurdes.)
Exercice facile c — tarif de cinéma
Raisonnement — Trois tranches d'âge, bornes à 4 et 18. On teste du plus petit au plus grand : age < 4, puis age < 18 (on sait déjà que age >= 4 : le elif le garantit), sinon plein tarif. Tester les âges charnières est la moitié de l'exercice : 3 (dernier gratuit), 4 (premier réduit), 17 (dernier réduit), 18 (premier plein).
Solution
# ex-02-1-c.py
age = int(input("Age ? "))
if age < 4:
print("Gratuit")
elif age < 18: # ici age >= 4 est garanti par la position
print("Prix : 5.50 EUR")
else: # ici age >= 18
print("Prix : 9.20 EUR")
Sorties pour 3, 4, 17, 18 : Gratuit, Prix : 5.50 EUR, Prix : 5.50 EUR, Prix : 9.20 EUR.
Pourquoi ça marche — La chaîne trie les âges par seuils croissants avec < strict : 4 échoue au premier test (4 < 4 est faux) et tombe dans le tarif réduit — exactement la consigne « de 4 à 17 ans ». Chaque elif hérite de la négation des tests précédents : pas besoin de 4 <= age < 18.
Erreur classique sur cet exercice — Le mauvais opérateur à la borne : age <= 4 fait payer les enfants de 4 ans au tarif gratuit — off-by-one de condition, aucun message d'erreur, seul le test des charnières l'attrape. C'est tout l'intérêt de tester 3 ET 4, pas juste 10.
Variante plus difficile — Ajoute un tarif senior (65 ans et plus, 7.00 EUR) et décide : où le placer dans la chaîne, et pourquoi l'ordre < 4, < 18, >= 65, else fonctionne-t-il quel que soit l'âge ?
Exercice moyen a — les deux bugs de l'âge
Raisonnement — On lit le programme comme Python. Ligne 2 : if age = 18: — un = d'assignation dans une condition : bug bruyant, SyntaxError immédiate, AUCUNE ligne n'est exécutée (pas même l'input). Une fois corrigé en ==, le programme tourne… et le deuxième bug se révèle : age vient d'un input() jamais converti, donc age == 18 compare "18" à 18 → False silencieux, et age > 18 lève TypeError: '>' not supported between instances of 'str' and 'int'. Deux bugs, deux familles : syntaxe et types.
Solution
# ex-02-1-d.py — version corrigée
age = int(input("Ton age ? ")) # bug 2 corrigé : conversion
if age == 18: # bug 1 corrigé : == compare
print("Pile la majorite !")
elif age > 18:
print("Majeur")
else:
print("Mineur")
Pourquoi ça marche — == pose la question au lieu d'assigner ; int() rend les comparaisons homogènes (int contre int). L'ordre des branches est correct : le cas exact (== 18) avant le cas large (> 18) — dans l'autre sens, 18 tomberait-il dans « Pile la majorité » ? (Oui, car 18 > 18 est faux — mais réfléchis-y avec >=, et tu vois pourquoi on met le cas précis d'abord par principe.)
Erreur classique sur cet exercice — Corriger le = (le message d'erreur le crie) et déclarer victoire sans tester : le TypeError n'apparaît que si on tape un âge NON égal à 18… et le False silencieux de "18" == 18 ne se voit que si on tape exactement 18. Moralité : corriger un bug ≠ avoir tout corrigé — re-teste toutes les branches.
Variante plus difficile — Sans corriger la conversion, quelles saisies font planter le programme et lesquelles donnent juste une réponse fausse ? (Réponse : tout ce qui atteint age > 18 plante en TypeError ; la saisie 18 donne « Mineur » — faux, silencieux, le pire des deux.)
Exercice moyen b — la chaîne dans le désordre
Raisonnement — 95 >= 50 est vrai → premier bloc exécuté → Passable, et Python saute le reste de la chaîne. Les conditions >= 70 et >= 90 sont inatteignables : tout score qui les vérifie vérifie AUSSI >= 50, testé avant. Règle : avec des seuils, tester du plus exigeant au moins exigeant.
Solution
# ex-02-1-e.py — version corrigée
score = 95
if score >= 90:
print("Excellent")
elif score >= 70:
print("Bien")
elif score >= 50:
print("Passable")
else:
print("Echoue")
Vérification : 95 → Excellent, 72 → Bien, 50 → Passable, 30 → Echoue.
Pourquoi ça marche — En descendant du seuil le plus haut, chaque elif sait que le score est SOUS les seuils précédents : les tranches se découpent proprement sans écrire les bornes doubles.
Erreur classique sur cet exercice — « Corriger » en gardant l'ordre mais en fermant les tranches (if 50 <= score < 70: etc.) : ça marche, mais c'est plus long, et une faute de frappe dans UNE borne crée un trou (un score de 70 pile sans réponse). Le tri décroissant des seuils est plus robuste.
Variante plus difficile — Que se passe-t-il pour un score de 70 pile dans TA version ? Et 89 ? Vérifie que chaque valeur charnière tombe dans la bonne tranche — c'est le même « test des bornes » que l'exercice c.
Exercice moyen c — parité et signe imbriqués
Raisonnement — Deux questions indépendantes (pair/impair, positif/négatif) → 4 cas. Sans and (interdit ici, il arrive en 02-2), on emboîte : un if extérieur décide la parité (n % 2 == 0, leçon 01-2), et DANS chaque branche, un if intérieur décide le signe. 0 doit sortir « pair positif » → le test de signe est >= 0, pas > 0.
Solution
# ex-02-1-f.py
n = int(input("Un nombre entier ? "))
if n % 2 == 0: # pair
if n >= 0:
print("pair positif")
else:
print("pair negatif")
else: # impair
if n >= 0:
print("impair positif")
else:
print("impair negatif")
Vérification : 4 → pair positif, -4 → pair negatif, 7 → impair positif, -7 → impair negatif, 0 → pair positif.
Pourquoi ça marche — Chaque else est accroché au if de même indentation : les deux tests intérieurs (8 espaces) appartiennent chacun à leur branche extérieure. Les 4 chemins sont exclusifs et couvrent tout.
Erreur classique sur cet exercice — Dé-indenter le deuxième if n >= 0: et son bloc : il sort de la branche else extérieure et s'exécute TOUJOURS — un nombre pair affiche alors deux lignes. Aucune erreur Python : c'est le bug d'indentation « légale mais fausse » (⏩ disséqué en 02-5). Relis l'imbrication en suivant les niveaux au doigt.
Variante plus difficile — Réécris avec 4 branches à plat : if/elif/elif/else et des conditions doubles… impossible proprement sans and, n'est-ce pas ? Garde cette frustration au chaud : c'est exactement ce que la leçon 02-2 résout. Reviens réécrire cet exercice après.
Exercice difficile a — le plus grand de trois
Raisonnement — Comparer a et b donne un « champion provisoire » ; il reste à le confronter à c. Deux niveaux d'imbrication suffisent : 4 chemins, chacun désignant un gagnant. On stocke le gagnant dans une variable (biggest) au lieu d'imprimer dans chaque branche : une seule ligne d'affichage, et la partie « ex aequo » peut réutiliser la valeur. Pour l'ex aequo : compter combien des trois valent biggest.
Solution
# ex-02-1-g.py
a = int(input("a ? "))
b = int(input("b ? "))
c = int(input("c ? "))
if a >= b:
if a >= c:
biggest = a
else:
biggest = c
else:
if b >= c:
biggest = b
else:
biggest = c
count = 0 # combien de valeurs égalent le maximum ?
if a == biggest:
count = count + 1
if b == biggest:
count = count + 1
if c == biggest:
count = count + 1
if count >= 2:
print(f"ex aequo : {biggest}")
else:
print(f"le plus grand : {biggest}")
Vérification : 3 9 5 → le plus grand : 9 ; 7 7 2 → ex aequo : 7 ; 5 5 5 → ex aequo : 5 ; 9 3 5 → le plus grand : 9.
Pourquoi ça marche — Le premier if élimine une comparaison : si a >= b, b ne peut plus être le maximum strict, inutile de le comparer à c. Les trois if de comptage sont des if SÉPARÉS (pas elif) : chaque valeur doit être testée, même quand une précédente a déjà compté — c'est le cas d'usage légitime des if en série.
Erreur classique sur cet exercice — Utiliser > strict dans la cascade : avec 7 7 2, a > b est faux → on passe dans le else → b >= c → biggest = 7… ça marche ici, mais trace 2 7 7 et 7 2 7 pour te convaincre que >= est le choix qui ne dépend pas de la position des égaux. Autre classique : faire les comptages en elif — 7 7 2 ne compte alors qu'un seul 7 et l'ex aequo disparaît.
Variante plus difficile — Affiche aussi le plus PETIT des trois sans refaire de saisie, puis la différence max − min. Et si tu veux voir le futur : au niveau 3, max(a, b, c) fera la cascade en un mot — mais tu sauras ce qu'il fait dedans.
Mini-projet — le convertisseur à menu
Raisonnement — On suit les étapes de la fiche : d'abord UNE conversion qui marche (vérifiée avec 0 °C → 32 °F et 100 °C → 212 °F), puis le menu, puis le branchement if/elif, puis le else des choix invalides. Le choix est comparé comme chaîne ("1") — c'est le piège central. Chaque branche fait sa propre saisie de valeur : on ne demande pas de valeur pour un choix invalide.
Solution
# converter.py
print("Convertisseur d'unites")
print("1. Celsius -> Fahrenheit")
print("2. Kilometres -> Miles")
print("3. Kilogrammes -> Livres")
choice = input("Ton choix : ")
if choice == "1":
celsius = float(input("Valeur : "))
fahrenheit = celsius * 9 / 5 + 32
print(f"{celsius:.1f} degC = {fahrenheit:.1f} degF")
elif choice == "2":
km = float(input("Valeur : "))
miles = km * 0.621371
print(f"{km:.1f} km = {miles:.1f} miles")
elif choice == "3":
kg = float(input("Valeur : "))
pounds = kg * 2.20462
print(f"{kg:.1f} kg = {pounds:.1f} livres")
else:
print(f"Choix inconnu : {choice}. Relance et tape 1, 2 ou 3.")
Session (choix 1, valeur 25) :
Convertisseur d'unites
1. Celsius -> Fahrenheit
2. Kilometres -> Miles
3. Kilogrammes -> Livres
Ton choix : 1
Valeur : 25
25.0 degC = 77.0 degF
Points de contrôle vérifiés : 0 °C → 32.0 degF ; 100 °C → 212.0 degF ; 100 km → 62.1 miles ; 1 kg → 2.2 livres ; choix 7 → message propre, pas de traceback.
Pourquoi ça marche — choice == "1" compare des chaînes entre elles : homogène, fiable. Le formatage :.1f est fait à l'affichage, pas dans le calcul (consigne de la fiche) : la valeur reste exacte, seule la sortie est arrondie. Le else final rend le programme inusable… au sens noble : aucune saisie de menu ne peut le faire planter.
Erreur classique sur cet exercice — if choice == 1: (l'entier) : aucune branche ne matche jamais, tout tombe dans le else — pas de plantage, juste un menu qui « ne marche pas ». Débogage éclair : print(choice, type(choice)) (le réflexe qui deviendra officiel en 02-5). Autre écueil de la fiche : taper 25,5 avec une virgule → ValueError sur float() — signale « point décimal » dans le message d'invite si ça t'arrive.
Variante plus difficile — Les extensions de la fiche : conversions inverses (menu à 6 choix — ta chaîne elif s'allonge, c'est mécanique), puis, dès la leçon 02-3 : boucler sur le menu jusqu'à un choix « q », et redemander la valeur tant qu'elle est invalide.