backend / python
Boucles for et while
Explication
Ce que vous allez apprendre
- Choisir entre
foretwhileselon que le nombre d'itérations est connu à l'avance ou non - Utiliser
enumerate()etzip()pour éviter de gérer des indices à la main - Contrôler précisément le flux d'une boucle avec
break,continueet la clauseelse - Repérer pourquoi modifier une liste pendant qu'on la parcourt cause des bugs difficiles à voir
- Écrire une boucle
while Truesûre, avec une condition de sortie garantie
Dans quel contexte ?
Un développeur écrit une fonction trouver_utilisateur_actif(utilisateurs) qui doit parcourir une liste et retourner le premier utilisateur dont statut == "actif", ou signaler qu'aucun n'a été trouvé. Sans la clause else d'une boucle for, il devrait introduire une variable trouve = False supplémentaire juste pour savoir, après coup, si la recherche a abouti — la clause else rend ce code plus court et plus clair.
Répéter sans se répéter
Écrire vingt fois la même instruction pour traiter vingt éléments serait absurde. Les boucles existent pour exécuter un bloc de code plusieurs fois sans dupliquer le code source. Python propose deux boucles aux usages différents : for parcourt une collection élément par élément (on sait à l'avance sur quoi on itère), et while répète tant qu'une condition reste vraie (on ne sait pas forcément combien de fois).
| Boucle | Utiliser quand... | Exemple |
|---|---|---|
for | Le nombre d'éléments à parcourir est connu | for ligne in fichier: |
while | On répète jusqu'à une condition, sans savoir combien de fois | while connexion.en_attente(): |
while True + break | La sortie dépend d'un événement interne à la boucle | Lire un flux jusqu'à un signal d'arrêt |
for en Python n'est pas un compteur
Dans beaucoup de langages, une boucle for manipule un indice numérique. En Python, for element in collection parcourt directement les éléments, pas des indices. Si vous avez besoin de l'indice, enumerate() vous l'offre proprement plutôt que de le gérer à la main avec un compteur externe. De même, zip() permet de parcourir plusieurs séquences en parallèle sans jongler avec des indices.
Contrôler le flux à l'intérieur
break arrête complètement la boucle, continue saute uniquement à l'itération suivante. Une subtilité peu connue mais élégante : une boucle peut avoir une clause else, exécutée uniquement si elle s'est terminée normalement, sans break. C'est un outil précieux pour des algorithmes de recherche : si j'ai parcouru toute la liste sans rien trouver, alors...
Piège fréquent
Supprimer des éléments d'une liste avec for item in liste: liste.remove(item) saute silencieusement certains éléments, car Python déplace les indices restants pendant que la boucle avance. La solution sûre : parcourir une copie (for item in liste[:]) ou construire une nouvelle liste filtrée.
Pièges fréquents
Modifier une liste pendant qu'on la parcourt avec un for peut provoquer des comportements imprévisibles (des éléments sautés). Et une boucle while True mal maîtrisée devient vite une boucle infinie si la condition de sortie n'est jamais atteinte.
Après avoir appris à choisir (leçon précédente) et maintenant à répéter, vous avez les deux briques de contrôle de flux fondamentales. Les prochaines leçons s'appuient constamment dessus, notamment pour construire des listes et des dictionnaires.
Commandes & code
Boucles for et while
Repeter des instructions, avec controle fin du flux.
# for sur un iterable
fruits = ["pomme", "banane", "cerise"]
for fruit in fruits:
print(fruit)
# range() : sequence d'entiers, sans creer de liste en memoire
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 10, 2): # start, stop, step -> 2, 4, 6, 8
print(i)
# enumerate() : obtenir l'index sans compteur manuel
for index, fruit in enumerate(fruits, start=1):
print(f"{index}. {fruit}")
# zip() : parcourir plusieurs iterables en parallele
noms = ["Ana", "Bo", "Cy"]
scores = [92, 78, 85]
for nom, score in zip(noms, scores):
print(f"{nom} : {score}")
# while : tant qu'une condition est vraie
compteur = 0
while compteur < 3:
print(f"Iteration {compteur}")
compteur += 1
# break / continue
for n in range(10):
if n == 5:
break # sort de la boucle
if n % 2 == 0:
continue # passe a l'iteration suivante
print(n) # affiche 1, 3
# clause else sur une boucle (execute si pas de break) : peu connue mais utile
def contient_premier(liste):
for n in liste:
if n < 2:
continue
for d in range(2, int(n ** 0.5) + 1):
if n % d == 0:
break
else:
return n # aucun diviseur trouve : n est premier
return None
print(contient_premier([4, 6, 8, 9, 11, 15])) # 11
# Boucle infinie controlee : pattern courant pour lire un flux
def lire_lignes(source):
while True:
ligne = next(source, None)
if ligne is None:
break
yield ligne.strip()
# Parcours inverse et par pas
for i in range(10, 0, -1):
print(i, end=" ")
print()
liste = list(range(20))
print(liste[::2]) # un element sur deux
print(liste[::-1]) # inverseeRésumé
for ... in ...parcourt un iterable,whileboucle sur une condition.enumerate()etzip()evitent les compteurs manuels et les indices.break/continuecontrolent le flux ;elsesur une boucle s'execute seulement sansbreak.
Exercices pratiques
Mission : corriger un script de nettoyage qui saute des lignes
Objectif : Diagnostiquer pourquoi une boucle qui modifie une liste en la parcourant saute des éléments, puis réécrire un algorithme de recherche avec la clause else.
Contexte
Un script doit nettoyer une liste de commandes en supprimant celles marquées "annulée", avec for commande in commandes: commandes.remove(commande) si elle est annulée. Le résultat final contient encore des commandes annulées, alors que le développeur jure avoir bien parcouru toute la liste.
Tu dois expliquer ce bug classique, réécrire le nettoyage correctement, puis utiliser la clause else d'une boucle for pour un algorithme de recherche.