1. Les modules de la bibliothèque standard
Python est livré avec des centaines de modules prêts à l’emploi. Quelques-uns très utiles :
| Module | Utilité | Exemple |
|---|---|---|
math | Fonctions mathématiques | math.sqrt(16), math.pi |
random | Hasard | random.shuffle(liste) |
datetime | Dates et heures | datetime.now() |
time | Pauses, chronomètre | time.sleep(1) |
os, pathlib | Fichiers et dossiers | Path("data").mkdir() |
turtle | Dessin (idéal pour s’amuser) | turtle.forward(100) |
hashlib, secrets | Sécurité : empreintes, aléatoire sûr | secrets.token_hex(8) |
from math import sqrt, pi # importer seulement certaines fonctions
import datetime as dt # donner un nom court au module
print(sqrt(2))
print(f"Aire d'un disque de rayon 3 : {pi * 3 ** 2:.2f}")
print(dt.date.today())
Dessiner avec turtle
import turtle
t = turtle.Turtle()
t.speed(0)
for i in range(36):
for cote in range(4): # un carré
t.forward(100)
t.left(90)
t.left(10) # on tourne un peu avant le suivant
turtle.done()
2. Les bibliothèques externes et pip
Au-delà de la bibliothèque standard, des centaines de milliers de bibliothèques sont publiées sur PyPI (pypi.org). On les installe avec pip. Dans Thonny, le plus simple est le menu Outils → Gérer les paquets. En ligne de commande :
pip install requests # requêtes web
pip install matplotlib # graphiques
3. Les empreintes (hash) : stocker un mot de passe correctement
Une fonction de hachage transforme un texte en une empreinte de longueur fixe. Il est impossible de retrouver le texte d’origine à partir de l’empreinte, mais le même texte donne toujours la même empreinte. On peut donc vérifier un mot de passe sans le stocker.
import hashlib, secrets
def hacher(mdp, sel=None):
"""Renvoie (sel, empreinte). Le sel rend chaque empreinte unique."""
if sel is None:
sel = secrets.token_hex(16)
empreinte = hashlib.pbkdf2_hmac("sha256", mdp.encode(), sel.encode(), 200_000)
return sel, empreinte.hex()
def verifier(mdp, sel, empreinte_attendue):
_, empreinte = hacher(mdp, sel)
return secrets.compare_digest(empreinte, empreinte_attendue)
sel, h = hacher("MaPhrase-De-Passe-2026!")
print(verifier("MaPhrase-De-Passe-2026!", sel, h)) # True
print(verifier("mauvais", sel, h)) # False
Note aussi secrets au lieu de random : random est prévisible et convient aux jeux, secrets est conçu pour générer des codes et jetons sûrs.
4. Découvrir la programmation orientée objet
Jusqu’ici, les données (dictionnaires) et les traitements (fonctions) étaient séparés. Une classe regroupe les deux : c’est un « plan de fabrication » d’objets qui ont des attributs (données) et des méthodes (fonctions qui leur sont propres).
class CompteBancaire:
def __init__(self, titulaire, solde=0): # constructeur
self.titulaire = titulaire # attributs
self.solde = solde
def deposer(self, montant): # méthode
if montant <= 0:
raise ValueError("Montant invalide")
self.solde += montant
def retirer(self, montant):
if montant > self.solde:
return False
self.solde -= montant
return True
def __str__(self): # affichage avec print
return f"{self.titulaire} : {self.solde:.2f} €"
compte = CompteBancaire("Léa", 100) # création d'un objet
compte.deposer(50)
compte.retirer(30)
print(compte) # Léa : 120.00 €
self désigne l’objet lui-même. raise lève une exception volontairement, pour signaler une utilisation incorrecte. La POO est un vaste sujet : cet aperçu te permettra de reconnaître des classes dans le code des autres et de t’y former ensuite.
5. Méthode de projet
Un programme de plus de quelques dizaines de lignes ne s’écrit pas d’un bloc. Voici la démarche des professionnels, à appliquer à ton projet final :
- Cahier des charges : écris en français ce que le programme doit faire, et ce qu’il ne fera pas.
- Données : quelles informations faut-il mémoriser ? Sous quelle forme (liste, dictionnaire, fichier) ?
- Découpage : liste les fonctions nécessaires, chacune avec une seule responsabilité.
- Développement incrémental : programme une fonction, teste-la, puis passe à la suivante. Le programme doit fonctionner à chaque étape.
- Tests : des
assertpour les fonctions de calcul, des essais « méchants » pour les saisies (texte vide, lettres, nombres négatifs…). - Relecture : noms clairs, commentaires utiles, pas de code dupliqué.
6. Projet final : le jeu du pendu
Découpage proposé
| Fonction | Rôle |
|---|---|
charger_mots(chemin) | Renvoie la liste des mots du fichier (liste par défaut si fichier absent) |
sans_accent(texte) | Remplace é, è, ê, à, ç… par la lettre simple |
masquer(mot, lettres_trouvees) | Renvoie le mot avec des _ pour les lettres non trouvées |
demander_lettre(deja_proposees) | Saisie contrôlée d’une lettre nouvelle |
jouer_partie() | Déroule une partie, renvoie le mot et le nombre d’erreurs |
charger_scores() / enregistrer_score() | Lecture et écriture du fichier JSON |
afficher_top5() | Trie les scores et affiche les 5 meilleurs |
main() | Menu : jouer, voir les scores, quitter |
7. Et après ?
Tu as maintenant les bases solides de la programmation. Selon tes envies :
| Direction | Pour faire quoi | À explorer |
|---|---|---|
| Jeux | Jeux 2D, animations | pygame |
| Web | Sites et applications web | Flask, puis HTML/CSS |
| Données | Tableaux, statistiques, graphiques | pandas, matplotlib |
| Automatisation | Renommer des fichiers, traiter des Excel, des PDF | pathlib, openpyxl |
| Cybersécurité | Comprendre les attaques pour s’en défendre | Plateformes légales type Root-Me, TryHackMe |
| Électronique | Capteurs, robots, domotique | Raspberry Pi, micro:bit, MicroPython |
8. Bilan final
Exercices corrigés
Pour le projet final, ta version peut être très différente de celle-ci : c’est normal et même souhaitable. Compare surtout le découpage et la robustesse, puis pioche dans le corrigé les idées qui t’intéressent.
Exercice 7.1 — Créations
Voir le corrigé
import turtle
from datetime import datetime
def polygone(t, nb_cotes, longueur):
for i in range(nb_cotes):
t.forward(longueur)
t.left(360 / nb_cotes)
t = turtle.Turtle()
for n in (3, 6, 8):
polygone(t, n, 80)
turtle.done()
saisie = input("Date de naissance (jj/mm/aaaa) : ")
naissance = datetime.strptime(saisie, "%d/%m/%Y")
print(f"Tu as vécu {(datetime.now() - naissance).days} jours.")
Explication
L’angle extérieur d’un polygone régulier vaut 360 / nb_cotes : c’est de combien la tortue doit tourner à chaque sommet. strptime transforme un texte en date selon un format ; la soustraction de deux dates donne une durée dont .days est le nombre de jours.
Exercice 7.2 — Ma première classe
Voir le corrigé
class Livre:
def __init__(self, titre, auteur):
self.titre = titre
self.auteur = auteur
self.emprunte = False
def emprunter(self):
if self.emprunte:
return False
self.emprunte = True
return True
def rendre(self):
self.emprunte = False
biblio = [Livre("Germinal", "Zola"), Livre("Candide", "Voltaire"), Livre("Nana", "Zola")]
biblio[0].emprunter()
for livre in biblio:
if not livre.emprunte:
print(f"Disponible : {livre.titre} ({livre.auteur})")
Explication
__init__ initialise chaque nouvel objet ; self permet à chaque livre d’avoir ses propres valeurs. emprunter() renvoie un booléen pour que le programme sache si l’opération a réussi.
Pour aller plus loin
def __str__(self):
etat = "emprunté" if self.emprunte else "disponible"
return f"{self.titre} ({self.auteur}) - {etat}"
Avec cette méthode ajoutée à la classe, print(livre) affiche directement une description lisible.
Projet final — Le pendu
Voir le corrigé
import random, json
from datetime import datetime
VIES = 7
FICHIER_SCORES = "scores.json"
ACCENTS = {"é": "e", "è": "e", "ê": "e", "ë": "e", "à": "a", "â": "a",
"î": "i", "ï": "i", "ô": "o", "ù": "u", "û": "u", "ç": "c"}
def sans_accent(texte):
return "".join(ACCENTS.get(c, c) for c in texte.lower())
def charger_mots(chemin="mots.txt"):
try:
with open(chemin, encoding="utf-8") as f:
mots = [l.strip().lower() for l in f if l.strip().isalpha()]
if mots:
return mots
except FileNotFoundError:
pass
return ["python", "ordinateur", "variable", "fonction", "élève"]
def masquer(mot, trouvees):
return " ".join(c if sans_accent(c) in trouvees else "_" for c in mot)
def demander_lettre(deja):
while True:
l = sans_accent(input("Lettre : ").strip())
if len(l) != 1 or not l.isalpha():
print("Une seule lettre, s'il te plaît.")
elif l in deja:
print("Déjà proposée.")
else:
return l
def jouer_partie():
mot = random.choice(charger_mots())
lettres_mot = set(sans_accent(mot))
trouvees, ratees = set(), set()
while len(ratees) < VIES and not lettres_mot <= trouvees:
print(f"\n{masquer(mot, trouvees)} vies : {VIES - len(ratees)}")
l = demander_lettre(trouvees | ratees)
if l in lettres_mot:
trouvees.add(l)
else:
ratees.add(l)
gagne = lettres_mot <= trouvees
print(("Gagné ! " if gagne else "Perdu... ") + f"Le mot était : {mot}")
return mot, len(ratees), gagne
def charger_scores():
try:
with open(FICHIER_SCORES, encoding="utf-8") as f:
donnees = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return []
# on ne garde que les scores bien formés
return [s for s in donnees if isinstance(s, dict)
and isinstance(s.get("erreurs"), int) and isinstance(s.get("nom"), str)]
def enregistrer_score(nom, mot, erreurs):
scores = charger_scores()
scores.append({"nom": nom, "mot": mot, "erreurs": erreurs,
"date": datetime.now().strftime("%d/%m/%Y")})
with open(FICHIER_SCORES, "w", encoding="utf-8") as f:
json.dump(scores, f, indent=2, ensure_ascii=False)
def afficher_top5():
scores = sorted(charger_scores(), key=lambda s: s["erreurs"])
for i, s in enumerate(scores[:5], 1):
print(f"{i}. {s['nom'][:20]:<20} {s['erreurs']} erreur(s) {s.get('date', '')}")
def main():
while True:
choix = input("\n1 Jouer 2 Top 5 3 Quitter > ")
if choix == "1":
mot, erreurs, gagne = jouer_partie()
if gagne:
nom = input("Ton pseudo : ").strip()[:20] or "Anonyme"
enregistrer_score(nom, mot, erreurs)
elif choix == "2":
afficher_top5()
elif choix == "3":
break
main()
Nouveautés utilisées : les ensembles (set, collection sans doublons, <= teste l’inclusion), les expressions génératrices dans join et lambda (petite fonction anonyme utilisée comme critère de tri). Chacune se découvre facilement dans la documentation : c’est ta première occasion d’apprendre en autonomie.
Explication
Les ensembles (set) simplifient beaucoup le jeu : lettres_mot <= trouvees vérifie que toutes les lettres du mot ont été trouvées, et trouvees | ratees réunit toutes les lettres déjà proposées. Chaque fonction est testable séparément, par exemple masquer("chat", {"a"}) doit donner _ _ a _.
Pour aller plus loin
# Tests unitaires à placer avant main()
assert sans_accent("Élève") == "eleve"
assert masquer("chat", {"a"}) == "_ _ a _"
assert masquer("été", {"e"}) == "é _ é"
🧠 Testez vos connaissances
5 questions. Répondez puis cliquez sur « Corriger ». Rien n’est enregistré : c’est de l’auto-évaluation.
© 2026 Bruno Jousseaume. Ce cours est publié sous licence CC BY-NC-SA 4.0 : vous pouvez le partager et l’adapter en citant l’auteur et un lien vers cette page, sans usage commercial, et en partageant vos adaptations sous la même licence.