Solutions — série 01-1 (print, variables et premiers programmes)

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 — trois variables, une f-string

Raisonnement — Trois informations à stocker, une phrase à produire. On crée une variable par information (noms en anglais, explicites), puis UNE seule f-string qui les assemble. Aucun calcul : c'est un exercice de syntaxe pure — le but est d'écrire une f-string juste du premier coup.

Solution

# ex-01-1-a.py
first_name = "Jean"
city = "Nice"
birth_year = 1984

print(f"Je m'appelle {first_name}, j'habite à {city} et je suis né en {birth_year}.")

Sortie :

Je m'appelle Jean, j'habite à Nice et je suis né en 1984.

Pourquoi ça marche — Le f devant les guillemets active le remplacement : chaque {nom} est remplacé par la valeur de la variable. birth_year est un int ; la f-string le convertit automatiquement en texte pour l'affichage — c'est l'un des grands conforts des f-strings.

Erreur classique sur cet exercice — Oublier le f : le programme affiche alors littéralement Je m'appelle {first_name}..., sans aucune erreur. C'est un bug silencieux : toujours relire sa sortie. Variante fréquente : mettre les guillemets autour du nom dans les accolades ({"first_name"}), ce qui affiche le texte first_name au lieu de la valeur.

Variante plus difficile — Affiche la même phrase SANS f-string, uniquement avec print() et des virgules (print("Je m'appelle", first_name, ...)). Compare la lisibilité des deux versions : tu comprendras pourquoi on standardise sur les f-strings.


Exercice facile b — prédire y

Raisonnement — On déroule le programme ligne par ligne, comme Python, avec l'image du post-it :

x = 5      # post-it « x » collé sur la valeur 5
y = x      # la DROITE est évaluée d'abord : x vaut 5 → post-it « y » collé sur 5
x = 10     # le post-it « x » est déplacé sur 10 ; « y » n'a pas bougé
print(y)

Solution — La sortie est :

5

Pourquoi ça marchey = x ne crée pas de lien permanent entre y et x. Python évalue la droite (x → la valeur 5) et colle le post-it y sur cette valeur-là. Quand x est réassigné à 10, on déplace le post-it x ; celui de y reste sur 5. Il n'existe pas, en Python, de variable qui « suit » une autre variable.

Erreur classique sur cet exercice — Répondre 10 en imaginant que y est un raccourci vers x (« y égale x, donc y vaut ce que vaut x maintenant »). C'est le modèle mental « formule de tableur », et il est faux : l'assignation se produit UNE fois, à l'instant où la ligne s'exécute.

Variante plus difficile — Prédis la sortie de :

x = 5
y = x
y = y + 1
print(x, y)

(Réponse : 5 6 — modifier y ne touche jamais x, pour la même raison. ⏩ Au niveau 3, avec les listes, cette intuition devra être raffinée : deux post-its sur LA MÊME liste voient les mêmes modifications.)


Exercice facile c — prix doublé calculé

Raisonnement — Deux contraintes : le doublé doit être calculé (donc price * 2 quelque part, jamais 39.98 tapé à la main), et l'affichage doit correspondre exactement au modèle. On peut calculer dans une variable intermédiaire (plus lisible, plus facile à déboguer) ou directement dans la f-string — les deux sont valables.

Solution

# ex-01-1-c.py
price = 19.99
doubled = price * 2

print(f"Prix : {price} € — Prix doublé : {doubled} €")

Sortie :

Prix : 19.99 € — Prix doublé : 39.98 €

Pourquoi ça marche — La droite de doubled = price * 2 est évaluée d'abord (19.99 * 239.98), puis assignée. Si le prix change un jour, une seule ligne à modifier et tout l'affichage reste juste : c'est exactement pourquoi on calcule au lieu de recopier.

Erreur classique sur cet exercice — Taper 39.98 en dur dans la f-string. Ça affiche la bonne sortie… aujourd'hui. Change price en 24.99 et l'affichage ment. Un programme qui recopie des résultats au lieu de les calculer n'est pas un programme, c'est une affiche.

Variante plus difficile — Avec price = 19.99, essaie print(price * 100) (le prix en centimes). Tu obtiendras 1998.9999999999998, pas 1999.0 : les nombres à virgule sont approximatifs. C'est le sujet de la leçon 01-2 (et son remède round()) — va la lire si la curiosité te démange.


Exercice moyen a — les deux bugs du compteur

Raisonnement — Le programme veut afficher Compteur : 3. On déroule à la main en suivant la valeur de counter ligne par ligne, puis on regarde l'affichage. Deux anomalies apparaissent :

  1. Ligne 4 : counter + 1 calcule 3… et jette le résultat. Sans =, le résultat n'est assigné à rien : counter vaut toujours 2 après cette ligne.
  2. Ligne 5 : print("Compteur : {counter}") — pas de f, donc la chaîne est affichée littéralement, accolades comprises.

Aucun des deux bugs ne produit de message d'erreur : ce sont deux bugs silencieux. Le programme affichait Compteur : {counter}.

Solution

# ex-01-1-d.py — version corrigée
counter = 0
counter = counter + 1
counter = counter + 1
counter += 1                    # bug 1 corrigé : le résultat est ASSIGNÉ
print(f"Compteur : {counter}")  # bug 2 corrigé : le f active le remplacement

Sortie :

Compteur : 3

Pourquoi ça marche — Une expression seule sur sa ligne (counter + 1) est légale : Python l'évalue puis oublie le résultat. Pour que le compteur avance, il faut recoller l'étiquette : counter = counter + 1 ou son raccourci counter += 1. Et sans f, une chaîne avec {...} n'est qu'un texte comme un autre.

Erreur classique sur cet exercice — Trouver le f manquant (visible dans la sortie) mais rater counter + 1, parce qu'« il y a bien un +1 sur la ligne ». Vérifie toujours qu'un calcul est assigné ou utilisé ; un calcul orphelin est presque toujours un bug.

Variante plus difficile — Sans exécuter : que vaudrait counter à la fin si la ligne 4 était counter = counter? Et counter =+ 1 (inversion de frappe pour +=) — pourquoi est-ce légal et que fait-il vraiment ? (Réponses : 2 ; counter =+ 1 se lit counter = +1, donc le compteur est écrasé à 1 — un piège de frappe redoutable car parfaitement silencieux.)


Exercice moyen b — "5" + 3, lire puis corriger

Raisonnement — L'exercice demande trois choses : provoquer l'erreur, la lire vraiment, proposer deux corrections aux résultats différents. Le point clé : + a deux métiers (additionner des nombres, coller des textes), et Python refuse de choisir à ta place quand les types sont mélangés.

Solution

Étape 1 — provoquer et lire :

# ex-01-1-e.py
a = "5"
b = 3
print(a + b)
Traceback (most recent call last):
  File "C:\Users\jtron\Claude\learnpython\lessons\level-01-bases\exercices\mes-reponses\ex-01-1-e.py", line 4, in <module>
    print(a + b)
          ~~^~~
TypeError: can only concatenate str (not "int") to str

Lecture de bas en haut : TypeError — Python a vu une str à gauche du +, a compris « concaténation », et refuse d'y coller un int. La ligne au-dessus montre le fichier, la ligne 4, et souligne a + b.

Étape 2 — les deux corrections :

print(int(a) + b)    # 8     : on convertit le texte en nombre → addition
print(a + str(b))    # 53    : on convertit le nombre en texte → collage

Pourquoi ça marcheint("5") fabrique le nombre 5 : les deux opérandes sont des int, + additionne. str(3) fabrique le texte "3" : les deux opérandes sont des str, + colle. Dans les deux cas on a rendu les types homogènes — c'est toujours ça, la correction d'un TypeError sur +.

Erreur classique sur cet exercice — Écrire int(a + b) : la conversion arrive TROP TARD, l'erreur explose à l'intérieur des parenthèses avant que int() ne voie quoi que ce soit. L'ordre d'évaluation (la droite/l'intérieur d'abord) s'applique aussi ici.

Variante plus difficile — Prédis le résultat de print(a * b) avec ces mêmes variables. (Réponse : 555 — multiplier une str par un int est légal et RÉPÈTE le texte. Surprenant, cohérent, et source de bugs quand on croyait avoir des nombres. ⏩ Les opérations sur chaînes sont approfondies en 01-3.)


Exercice difficile a — échanges sans a, b = b, a

Raisonnement — Si on fait a = b en premier, l'ancienne valeur de a est perdue à jamais (le post-it a été déplacé, plus rien ne pointe vers l'ancienne valeur). Il faut donc sauvegarder une valeur dans une variable temporaire avant de l'écraser. Pour trois variables, même logique : on sauvegarde UNE valeur, on fait tourner les autres, on repose la sauvegarde.

Solution

Échange de deux variables :

# ex-01-1-f.py
a = 1
b = 2

temp = a     # on pose la valeur de a en lieu sûr
a = b        # a est écrasé — pas grave, sa valeur est dans temp
b = temp     # b reçoit l'ANCIENNE valeur de a

print(a, b)  # 2 1

Rotation de trois variables (a→b, b→c, c→a), avec temporaire :

a = 1
b = 2
c = 3

temp = c     # c va être écrasé en dernier ressort : on le sauvegarde
c = b        # c reçoit l'ancienne valeur de b
b = a        # b reçoit l'ancienne valeur de a
a = temp     # a reçoit l'ANCIENNE valeur de c

print(a, b, c)   # 3 1 2

En une seule ligne :

a, b, c = 1, 2, 3
a, b, c = c, a, b
print(a, b, c)   # 3 1 2

Pourquoi ça marche — Version temporaire : à chaque écrasement, la valeur qui allait être perdue a déjà été copiée ailleurs. L'ordre des lignes est crucial — c'est un exercice d'ordre, pas de syntaxe. Version une ligne : Python évalue TOUTE la droite (c, a, b → les valeurs 3, 1, 2) avant la moindre assignation, donc aucune valeur n'est perdue — même mécanisme que a, b = b, a dans l'exemple 5 de la leçon.

Erreur classique sur cet exercice — Écrire la rotation dans le mauvais ordre sans temporaire :

b = a    # ✅ b vaut maintenant 1...
c = b    # ❌ c reçoit 1 (le NOUVEAU b), l'ancienne valeur 2 est perdue
a = c    # ❌ tout le monde vaut 1

Résultat : 1 1 1. Dérouler à la main, valeur par valeur, avant d'exécuter — c'est exactement le réflexe que cet exercice installe.

Variante plus difficile — L'échange de DEUX variables numériques sans variable temporaire ET sans la syntaxe a, b = b, a est possible avec de l'arithmétique : a = a + b, puis b = a - b, puis a = a - b. Déroule-le à la main avec a = 1, b = 2 pour te convaincre. (Astuce classique d'entretien ; en vrai code on écrit a, b = b, a, toujours.)


Mini-projet — « carte de présentation »

Raisonnement — Le projet teste trois choses : des variables bien nommées, des f-strings partout, et le réflexe « ne jamais taper deux fois la même chose » (la ligne de = vit dans une variable). On commence par lister les données, puis on construit l'affichage autour.

Solution

# presentation.py
# --- data ---------------------------------------------------------------
name = "Jean"
city = "Nice"
language = "Python"
goal = "autonomie en 12 semaines"
start_date = "2026-07-05"

# --- extension : durée écoulée -------------------------------------------
days_elapsed = 18
weeks_elapsed = days_elapsed // 7   # division entière : semaines COMPLÈTES
                                    # ⏩ // est expliqué en leçon 01-2

# --- display --------------------------------------------------------------
border = "=" * 40                   # la ligne est CONSTRUITE, pas tapée ;
                                    # stockée UNE fois, utilisée deux fois

print(border)
print(f"  {name} — {city}")
print(f"  Apprend : {language}")
print(f"  Objectif : {goal}")
print(f"  Depuis le : {start_date}")
print(f"  Semaines écoulées : {weeks_elapsed}")
print(border)

Sortie :

========================================
  Jean — Nice
  Apprend : Python
  Objectif : autonomie en 12 semaines
  Depuis le : 2026-07-05
  Semaines écoulées : 2
========================================

Pourquoi ça marche"=" * 40 répète le caractère 40 fois : la largeur de la carte se règle en changeant UN nombre. border est assignée une fois et utilisée deux fois : si tu veux passer à des -, une seule ligne change. days_elapsed // 7 donne le nombre de semaines complètes (18 // 72) — la division / aurait donné 2.5714…, faux pour un compteur de semaines.

Erreur classique sur cet exercice — Taper la ligne de = littéralement, deux fois. Ça marche… jusqu'au jour où tu élargis la carte et oublies UNE des deux lignes. La règle (elle a un nom : DRY, Don't Repeat Yourself) : toute valeur utilisée deux fois mérite une variable. Autre classique : oublier un f sur une seule des cinq lignes — relis la sortie ligne par ligne.

Variante plus difficile — (1) Ajoute days_remaining : l'objectif est à 12 semaines, affiche les jours restants, calculés (12 * 7 - days_elapsed). (2) Version « largeur paramétrable » : mets width = 40 en haut et construis border à partir de width ; vérifie qu'en changeant width à 50 TOUT s'adapte. (3) ⏩ Quand tu auras vu les méthodes de chaînes (01-3), tu pourras centrer les lignes avec str.center(width) — reviens améliorer cette carte.