La boucle for
L'idée : pour chaque élément d'une séquence
Faire l'appel en classe, c'est parcourir la liste des élèves : pour chaque élève, on applique la même procédure.
C'est exactement ce que fait la boucle for en Python. Son idée tient en une phrase :
La boucle for
Pour chaque élément, qu'on appelle x, d'une séquence, répéter un bloc d'instructions (avec cette valeur de x).
À chaque tour, x prend la valeur de l'élément suivant de la séquence. Le bloc doit être indenté.
c, puis h, puis a, puis t : un tour par caractère.
Ce que fait la machine, tour par tour
Déroulons for x in [10, 20, 30]: avec, dans le corps, print(x) :
| Tour | x prend la valeur |
ce qui s'affiche |
|---|---|---|
| 1 | 10 |
10 |
| 2 | 20 |
20 |
| 3 | 30 |
30 |
Quand il n'y a plus d'élément, la boucle s'arrête. Le point clé, c'est de savoir ce que vaut x à chaque tour.
range : un intervalle semi-ouvert d'entiers
Très souvent, on veut parcourir des entiers. Python fournit pour cela range, qui est la séquence représentant un intervalle semi-ouvert d'entiers.
range(a, b) représente l'intervalle semi-ouvert \([a\,;\,b)\) : la borne a est incluse, la borne b est exclue. Parcourir un range avec for, c'est donc « pour chaque entier de l'intervalle » :
Deux conséquences de l'intervalle semi-ouvert
range(n)vautrange(0, n): la séquence0, 1, ..., n-1, soitnentiers en partant de 0.- Comme
best exclu,b - aest exactement le nombre d'entiers parcourus.
Pourquoi ce choix n'est pas anodin
Exclure la borne haute peut sembler arbitraire. C'est en réalité un choix de conception qui fait disparaître à l'avance les erreurs de « plus ou moins un » (les bugs les plus fréquents chez les débutants) :
- les indices d'une séquence de longueur
nsont exactementrange(n): la longueur est la borne exclue, doncrange(len(s))donne pile les bons indices, jamais un de trop ni un de moins ; - pour couper une séquence à la position
k, les deux morceauxrange(0, k)etrange(k, n)se recollent sans trou ni doublon ; - l'intervalle vide s'écrit simplement
range(a, a).
Ce n'est donc pas une bizarrerie de Python, mais une convention argumentée, défendue notamment par Edsger Dijkstra (Why numbering should start at zero, note EWD 831, 1982).
Répéter n fois
« Répéter n fois » est simplement le cas où on parcourt range(n) sans se soucier de l'élément. Par convention, on nomme alors la variable _ (souligné), pour dire « je n'utilise pas cette valeur ».
L'accumulation : le motif fondamental
La plupart des problèmes se résolvent en construisant progressivement un résultat dans une variable appelée l'accumulateur. C'est le motif le plus important du cours.
Exemple : la somme des entiers de 1 à n.
- On crée l'accumulateur. Une somme d'entiers est un entier, il vaut
0au départ (on n'a rien ajouté) : - On parcourt les entiers de
1àn, doncrange(1, n + 1): - À chaque entier rencontré, on l'ajoute au résultat :
- À la fin de la boucle, tous les entiers ont été ajoutés :
Méthodologie de l'accumulation
- Je réfléchis au type de mon résultat et je l'initialise correctement.
- Qu'est-ce que je dois parcourir ? J'écris correctement mon parcours.
- Dans le parcours, j'applique à chaque élément le comportement d'accumulation voulu par le problème.
Le même for sur les autres séquences
Puisque for parcourt n'importe quelle séquence, il fonctionne à l'identique sur une chaîne, une liste, un tuple (les listes sont détaillées plus loin dans le cours). C'est le même mécanisme, on change seulement la séquence parcourue.
Il y a alors deux façons de parcourir une séquence s.
Par élément (à privilégier, plus lisible) :
Par indice, quand on a besoin de la position. Les indices de s vont de 0 à len(s) - 1, donc on parcourt range(len(s)) :
Là encore, c'est un for each : « pour chaque indice i dans range(len(s)) ».
Avant chaque exercice, deux questions
- Ce que je parcours (quelle séquence ?) ;
- comment je le parcours (par élément ou par indice ?).
Lire et prédire avant d'écrire
Avant d'écrire une boucle, entraînez-vous à lire celles des autres et à prédire leur résultat. C'est la meilleure préparation à en écrire soi-même.
Prédire (1)
Que vaut res à la fin ? Suivez-le tour par tour, puis exécutez pour vérifier.
Réponse
10. res prend successivement 0, 1, 3, 6, puis 10 (on ajoute 1, 2, 3, 4).
Prédire, puis modifier
- Prédisez l'affichage.
- Modifiez une seule ligne pour que le mot s'affiche à l'endroit.
Réponse
nohtyp: chaque lettre est placée devant les précédentes, donc la chaîne est renversée.- Remplacer
res = lettre + resparres = res + lettre.
Exercices
1 - Parcours simple
Affichez une par une les lettres demot, par élément, puis par indice.
2 - Un caractère sur deux
3 - Nombre de voyelles
On veut compter : que vaut le résultat au départ ? Complétez aussi le type de retour.
4 - Renverser
5 - Contient (sans l'opérateur in)
6 - Somme, produit, factorielle
somme(lst): la somme des entiers d'une liste.produit(lst): leur produit (attention à l'initialisation de l'accumulateur !).factorielle(n): \(1 \times 2 \times \dots \times n\). Que vautfactorielle(0)avec votre code ?
Indice léger
Reprenez la méthodologie de l'accumulation : de quel type est le résultat ? Quelle valeur initiale ne change rien à une addition ? à une multiplication ?
Indice plus précis
Pour la somme, l'accumulateur part de 0 et on fait res = res + x. Pour le produit, il part de 1 (car multiplier par 1 ne change rien) et on fait res = res * x.
7 - Minimum (sans la fonction min)
8 - Problème : bin2dec
Écrivez bin2dec(txt) qui convertit une écriture binaire (une chaîne de 0 et de 1) en entier décimal.
Indications : on peut renverser la chaîne pour que l'indice de chaque chiffre corresponde à sa puissance de 2, puis calculer la somme des puissances de 2 par accumulation (parcours par indice).
Le for s'arrête toujours : il fait un tour par élément d'une séquence finie. Quand on ne sait pas à l'avance combien de tours faire, on utilise l'autre boucle : La boucle non bornée while.