Leçon 01-2 — Types, nombres, input() et conversions

1. Objectif

À la fin de cette leçon tu sauras : reconnaître le type d'une valeur (int, float, str, bool) et le vérifier avec type(), calculer avec les opérateurs arithmétiques (y compris //, %, **), demander une donnée à l'utilisateur avec input(), et convertir entre types avec int(), float() et str() — en sachant exactement quand une conversion échoue et pourquoi.

2. Pourquoi c'est important

Le bug le plus fréquent des débutants — de très loin — est un mélange de types : additionner un texte et un nombre, calculer avec le résultat brut d'un input(), comparer des centimes en float. Tous les programmes réels manipulent des données qui arrivent sous forme de texte (saisie clavier, fichier, réponse web ⏩ niveau 9) et doivent les convertir en nombres avant de calculer. Cette leçon t'installe le réflexe qui t'évitera des heures de débogage : quel est le type de cette valeur, là, maintenant ?

3. Explication simple

En Python, chaque valeur a un type : sa nature, ce qu'on a le droit de faire avec.

42        # int   : nombre entier
3.14      # float : nombre à virgule (le POINT, pas la virgule !)
"42"      # str   : texte — même s'il ressemble à un nombre
True      # bool  : vrai ou faux (majuscule obligatoire)

La fonction type() te dit la nature d'une valeur :

print(type(42))     # <class 'int'>
print(type("42"))   # <class 'str'>

Retiens l'image : le type, c'est l'uniforme de la valeur. "42" porte l'uniforme « texte » : tu peux le coller à un autre texte, mais pas faire de maths avec. 42 porte l'uniforme « nombre » : l'inverse. Pour changer d'uniforme, il faut une conversion explicite : int("42") donne 42, str(42) donne "42". Python ne convertit jamais à ta place dans une addition — il préfère planter que deviner.

Dernière brique : input("question ") affiche la question, attend que l'utilisateur tape quelque chose, et retourne ce qu'il a tapé — toujours sous forme de str, même si l'utilisateur a tapé 42.

4. Explication approfondie

a) Les quatre types simples, précisément.

print(5 > 3)          # True
print(type(5 > 3))    # <class 'bool'>
print(0.1 + 0.2 == 0.3)   # False  (!)  — « == » teste l'égalité

⏩ Les comparaisons (==, <, >=…) et les décisions if sont le cœur du niveau 2. Ici tu dois seulement savoir que True/False existent, que c'est un type, et surtout que == (teste l'égalité) n'est pas = (assigne). Cette confusion produira des bugs au niveau 2 ; grave la différence maintenant.

b) Les opérateurs arithmétiques.

OpérateurNomExempleRésultat
+ - *addition, soustraction, multiplication7 * 214
/division vraie7 / 23.5
//division entière (quotient)7 // 23
%modulo (reste de la division)7 % 21
**puissance2 ** 101024

Deux subtilités que tout le monde rate :

  1. / retourne TOUJOURS un float, même quand la division tombe juste : 8 / 2 vaut 4.0, pas 4. Si tu veux un entier, c'est //.
  2. // arrondit vers le bas, pas vers zéro : -7 // 2 vaut -4 (pas -3). Rare au début, mais autant le savoir tout de suite.

Le couple // + % est l'outil de décomposition : 130 // 60 donne 2 (heures) et 130 % 60 donne 10 (minutes restantes). Tu t'en serviras sans arrêt.

c) Les flottants ne sont pas exacts — honnêtement.

print(0.1 + 0.2)    # 0.30000000000000004

Ce n'est pas un bug de Python : c'est vrai dans quasiment tous les langages. Un float est stocké en binaire, et 0.1 en binaire est un nombre infini périodique (comme 1/3 = 0.3333… en décimal). L'ordinateur le tronque, donc il stocke une valeur très proche de 0.1, pas 0.1. Additionne deux approximations, tu obtiens une approximation.

Conséquences pratiques :

Note honnête sur round() : sur le cas pile-poil .5, il arrondit vers le chiffre pair (round(2.5) vaut 2, round(3.5) vaut 4). C'est voulu (norme de calcul scientifique) et sans importance pour nous — mais si tu le croises, ce n'est pas un bug.

d) input() retourne TOUJOURS une str.

Toujours. Même si l'utilisateur tape 42. Même s'il tape 3.14. La règle mécanique à t'installer dans les doigts :

age = int(input("Ton âge ? "))        # saisie d'un entier
height = float(input("Ta taille ? ")) # saisie d'un nombre à virgule
name = input("Ton prénom ? ")         # saisie de texte : pas de conversion

e) Les conversions et leurs limites.

Difficulté honnête : cette leçon contient plus de pièges que la 01-1 (/ qui donne un float, int("3.5") qui plante, 0.1 + 0.2, l'input jamais converti). Prévois deux sessions : une pour les sections 1–7 en tapant tous les exemples, une pour les exercices. Le point (c) n'a pas besoin d'être maîtrisé en profondeur — retiens le symptôme et les deux remèdes (round, :.2f).

5. Exemples commentés

Exemple 1 — type() sur des littéraux

print(type(42))       # <class 'int'>
print(type(3.14))     # <class 'float'>
print(type("3.14"))   # <class 'str'>   ← guillemets = texte, point final
print(type(True))     # <class 'bool'>
print(type(7 / 7))    # <class 'float'> ← / donne TOUJOURS un float

Exemple 2 — le tableau des divisions, vérifié

print(7 / 2)     # 3.5
print(8 / 2)     # 4.0   ← float même quand ça tombe juste
print(7 // 2)    # 3     ← quotient entier
print(7 % 2)     # 1     ← reste
print(2 ** 10)   # 1024

Exemple 3 — décomposer avec // et %

total_minutes = 130
hours = total_minutes // 60       # 2   : combien d'heures complètes
minutes = total_minutes % 60      # 10  : ce qui reste
print(f"{total_minutes} min = {hours} h {minutes} min")

Sortie : 130 min = 2 h 10 min

Exemple 4 — les flottants approximatifs, et les deux remèdes

result = 0.1 + 0.2
print(result)                # 0.30000000000000004  ← brut : moche mais honnête
print(round(result, 2))      # 0.3                  ← remède 1 : round()
print(f"{result:.2f}")       # 0.30                 ← remède 2 : format .2f

Le :.2f dans une f-string signifie « affiche ce nombre avec exactement 2 chiffres après le point ». C'est un format d'affichage : la valeur stockée reste approximative, seul l'affichage est propre.

Exemple 5 — input() et la conversion obligatoire

raw = input("Année de naissance ? ")   # l'utilisateur tape : 1984
print(type(raw))                       # <class 'str'>  ← toujours !
birth_year = int(raw)                  # conversion explicite
age = 2026 - birth_year
print(f"Tu as environ {age} ans.")     # Tu as environ 42 ans.

En pratique on écrit directement birth_year = int(input("Année ? ")) — mais quand tu débogues, séparer les deux lignes te permet de print(type(raw)).

Exemple 6 — concaténer, c'est du texte ; additionner, c'est des nombres

a = "5"
b = "3"
print(a + b)              # 53     ← + entre deux str : COLLE les textes
print(int(a) + int(b))    # 8      ← + entre deux int : ADDITIONNE
print(str(4) + "2")       # 42     ← le texte "42", pas le nombre !

Même symbole +, deux métiers différents selon les uniformes en présence.

6. Erreurs fréquentes

1) Additionner un texte et un nombre

price = "5"
total = price + 3
# TypeError: can only concatenate str (not "int") to str

Python voit un str à gauche, comprend « concaténation », puis refuse de coller un int à un texte. Correction : int(price) + 38. (Et si tu voulais du texte : price + str(3)"53".) Pourquoi Python ne devine pas ? Parce que les deux réponses (8 et "53") sont légitimes — il préfère t'obliger à choisir.

2) Oublier de convertir un input()

age = input("Ton âge ? ")     # l'utilisateur tape 42... mais age vaut "42"
print(age + 1)
# TypeError: can only concatenate str (not "int") to str

C'est l'erreur n°1, la même que ci-dessus, mais camouflée : le programme marche jusqu'à la saisie, puis plante au calcul. Correction : age = int(input("Ton âge ? ")).

3) int() sur une valeur non convertible

count = int("abc")
# ValueError: invalid literal for int() with base 10: 'abc'

ValueErrorTypeError : ici le type de l'argument est acceptable (une str), c'est la valeur qui ne ressemble pas à un entier. Le message te montre la valeur coupable entre apostrophes — regarde-la toujours : c'est souvent une chaîne vide '' (l'utilisateur a juste appuyé sur Entrée).

4) int("3.5") plante aussi

size = int("3.5")
# ValueError: invalid literal for int() with base 10: '3.5'

Piège vicieux : int(3.5) (depuis un float) marche et donne 3, mais int("3.5") (depuis une str) plante. Une chaîne doit ressembler à un entier, point. Correction en deux étapes : int(float("3.5"))3.

5) S'attendre à un int après une division /

half = 8 / 2
print(half)      # 4.0   ← pas d'erreur, mais ce n'est PAS 4 (c'est un float)

Bug silencieux : aucun traceback, mais half est un float, et ton affichage montre 4.0 là où tu attendais 4. Si tu veux un entier : 8 // 2.

6) Écrire = en croyant tester une égalité

age = 18     # ceci ASSIGNE 18 à age — ça ne « vérifie » rien du tout

Tu n'as pas encore l'outil pour tester (==, ⏩ niveau 2), donc le piège est encore invisible — mais installe le vocabulaire dès maintenant : = assigne, == compare. Au niveau 2, if age = 18: te donnera une SyntaxError ; tu sauras immédiatement pourquoi.

7. Lire les messages d'erreur

Les deux exceptions emblématiques de cette leçon. Toujours de bas en haut.

TypeError — le mélange de types

Traceback (most recent call last):
  File "C:\Users\jtron\Claude\learnpython\age.py", line 2, in <module>
    print(age + 1)
          ~~~~^~~
TypeError: can only concatenate str (not "int") to str
  1. Dernière ligne : TypeError = opération interdite entre ces types. Le message dit exactement lesquels : un str à gauche, un int refusé.
  2. Au-dessus : fichier age.py, ligne 2, et le code fautif avec les ~~~~^~~ qui soulignent l'opération coupable (age + 1, le ^ sous le +).
  3. Réflexe : remonte à la création de la variable. D'où vient age ? D'un input() ligne 1 → c'est une str → conversion manquante. Le bug se déclare ligne 2 mais se corrige ligne 1. C'est très courant : la ligne du traceback est la ligne du symptôme, pas toujours celle de la cause.

ValueError — la conversion impossible

Traceback (most recent call last):
  File "C:\Users\jtron\Claude\learnpython\convert.py", line 1, in <module>
    age = int(input("Ton âge ? "))
ValueError: invalid literal for int() with base 10: 'quarante'
  1. Dernière ligne : ValueError = bon type d'argument, mauvaise valeur. invalid literal for int() = « ce texte ne ressemble pas à un entier », et la valeur coupable est affichée : 'quarante'.
  2. Au-dessus : ligne 1 de convert.py, c'est le int(...) qui a levé l'erreur — pas l'input(), qui lui a très bien marché. (Remarque : pas de soulignement ~~^~~ ici — Python ne le montre que lorsqu'il peut isoler une sous-partie de la ligne ; quand toute l'instruction est en cause, il n'y a rien à souligner.)
  3. Réflexe : cette erreur dépend de ce que l'utilisateur tape. Ton programme peut tourner dix fois puis planter à la onzième. On apprendra à s'en protéger avec try/except (⏩ niveau 5) ; pour l'instant, contente-toi de savoir la lire.

Distinction à mémoriser : TypeError = mauvais uniforme (opération interdite entre ces types). ValueError = bon uniforme, mauvaise valeur.

8. Exercices — faciles

Règles : nouveau fichier par exercice dans lessons/level-01-bases/exercices/mes-reponses/, nommé ex-01-2-a.py, etc. Tape tout à la main. Prédis la sortie AVANT d'exécuter.

a) Sans exécuter, écris sur papier le type ET la valeur affichés par chaque ligne, puis vérifie :

print(type(7))
print(type(7.0))
print(type("7"))
print(type(7 / 7))
print(type(7 // 7))
print(type(7 > 7))

b) Prédis les six sorties, puis vérifie :

print(9 / 2)
print(9 // 2)
print(9 % 2)
print(2 ** 4)
print(10 / 5)
print(10 % 5)

c) Demande à l'utilisateur son prénom puis son année de naissance (input() × 2). Calcule son âge approximatif en 2026 et affiche, en f-string : Bonjour Ada, tu as environ 42 ans. Contrainte : le calcul de l'âge doit être fait sur des int, pas des textes.

d) Crée budget = 100 et spent = 37.5. Affiche Reste : 62.50 € en utilisant le format :.2f. Puis affiche le type de budget - spent — explique en commentaire pourquoi ce n'est pas un int.

9. Exercices — moyens

a) Ce programme est censé afficher Dans 10 ans tu auras 52 ans. mais il plante. Trouve les DEUX bugs sans l'exécuter (ils ne sont pas sur la même ligne), puis corrige :

age = input("Ton âge ? ")
future_age = age + 10
print(f"Dans 10 ans tu auras {future-age} ans.")

b) Prédis la sortie EXACTE des quatre lignes (attention, c'est piégé), puis vérifie et note dans ton journal ce qui t'a surpris :

print(0.1 + 0.2)
print(round(0.1 + 0.2, 2))
print(1.1 + 2.2)
print(f"{1.1 + 2.2:.1f}")

c) Demande une durée en minutes (ex. 200) et affiche-la en heures + minutes : 200 min = 3 h 20 min. Contraintes : // et % obligatoires ; le programme doit afficher des entiers (pas 3.0 h).

10. Exercices — difficiles

a) Demande à l'utilisateur un nombre à TROIS chiffres (ex. 472) et affiche la somme de ses chiffres : 4 + 7 + 2 = 13. Contraintes : traiter le nombre comme un int — interdiction de découper le texte (⏩ le slicing de chaînes arrive en 01-3, on refera cet exercice autrement). Uniquement //, % et les notions de cette leçon.

11. Mini-projet lié — « convertisseur de devises »

Écris converter.py : un convertisseur euros → dollars à taux fixe.

Comportement attendu (exemple de session) :

=== Convertisseur EUR -> USD ===
Taux : 1 EUR = 1.08 USD
Montant en euros ? 250
250.00 EUR = 270.00 USD
Soit environ 270 dollars tout rond.

Contraintes :

Extension (facultative) : ajoute une deuxième conversion dans le même programme — le montant en dollars reconverti en euros — et vérifie que tu retombes (presque !) sur le montant de départ. Si l'affichage brut montre un truc comme 249.99999999999997, tu sais maintenant exactement pourquoi.

12. Correction / méthode de correction

Les solutions détaillées sont dans solutions/serie-01-2-solutions.md.

Méthode : (1) finis TOUS les exercices avant d'ouvrir les solutions ; (2) compare le raisonnement, pas seulement le code — une solution différente qui marche est souvent valable ; (3) pour chaque écart, écris une ligne dans ton journal : « je pensais X, en fait Y » ; (4) refais de tête l'exercice raté, le lendemain.

13. À retenir

14. Questions de révision

  1. Quel est le type de 8 / 2 ? Et de 8 // 2 ? Pourquoi la différence ?
  2. Pourquoi print(0.1 + 0.2) n'affiche-t-il pas 0.3 ? Cite les deux façons d'afficher proprement.
  3. Que retourne input() si l'utilisateur tape 3.14 ? Quel type ?
  4. Pourquoi int("3.5") plante-t-il alors que int(3.5) marche ? Que valent-ils ?
  5. Quelle est la différence entre un TypeError et un ValueError ? Donne un exemple de chaque.
  6. La ligne indiquée par un traceback est-elle toujours celle qu'il faut corriger ? Illustre avec l'erreur de l'input() non converti.
  7. Que valent 130 // 60 et 130 % 60 ? À quoi sert ce couple d'opérateurs ?
  8. Quelle est la différence entre = et == ?

15. Checklist de compréhension

Si une case reste vide : refais les exercices de la section correspondante demain, AVANT d'ouvrir la leçon suivante.

16. Commit conseillé

git add lessons/level-01-bases/exercices/mes-reponses/
git commit -m "exercises: complete lesson 01-2 types numbers input conversions"

Puis, si c'est ta fin de session : entrée de journal + git push.