= ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
gamme
print(gamme[0])
print(gamme[1])
print(gamme[2])
do
re
mi
Dans le tutoriel précédent, nous avons étudié les tests, qui permettent à un ordinateur de prendre des décisions selon des conditions spécifiées dans un programme. Nous allons à présent aller encore plus loin dans l’automatisation des opérations, grâce à la notion de boucle. Les boucles vont permettre de répéter plusieurs fois une instruction semblable sans avoir à réécrire le même code à chaque fois.
Pour illustrer cette idée, imaginons que l’on souhaite afficher chaque élément d’une liste. Pour l’instant, on ferait :
= ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
gamme
print(gamme[0])
print(gamme[1])
print(gamme[2])
do
re
mi
Et ainsi de suite. On voit tout de suite qu’une telle opération serait impraticable pour une liste contenant des centaines d’éléments. Les boucles vont résoudre ce problème de manière élégante et efficiente.
for
Le premier type de boucles auquel nous allons nous intéresser est la boucle for
. Une boucle for
permet de parcourir les différents éléments contenus dans un objet dit itérable, et de réaliser des opérations avec ces éléments. Les objets itérables incluent notamment tous les objets séquentiels que nous avons vus jusqu’à présent : chaînes de caractères, listes, tuples, etc.
Illustrons le fonctionnement d’une boucle for
en résolvant le problème exposé précédemment.
for note in gamme:
print(note)
do
re
mi
fa
sol
la
si
Analysons la structure d’une boucle for
:
La première ligne spécifie une instruction for
, et comme toute instruction en Python se termine par :
.
Vient ensuite un bloc d’instructions, i.e. une suite d’opérations (une seule dans notre exemple) qui sera exécutée à chaque itération de la boucle. Ce bloc est visible par son niveau d’indentation, incrémenté de 1 par rapport à l’instruction. Le bloc s’arrête dès lors que l’indentation revient à son niveau initial.
Comme pour les instructions conditionnelles de type if
/else
, l’indentation est donc capitale. Si on l’oublie, Python renvoie une erreur.
for note in gamme:
print(note)
do
re
mi
fa
sol
la
si
Regardons maintenant plus en détail ce que fait l’instruction for
. Elle définit une variable d’itération (appelée note
dans notre exemple), qui va parcourir les éléments de l’itérateur spécifié après le in
(la liste gamme
dans notre exemple). La syntaxe d’une boucle en Python se prête bien à une description littérale ; dans notre cas : “pour chaque note contenue dans la liste gamme, imprime la note”.
Insistons sur le fait qu’une boucle définit une variable, sans que l’on ait besoin de passer par la syntaxe traditionnelle d’assignation variable = valeur
. De plus, cette variable n’est pas supprimée une fois la boucle terminée, elle prend alors la valeur du dernier élément de l’itérateur.
note
'si'
L’itérateur n’est pas nécessairement une liste, il peut être tout objet itérable. Cela inclut notamment tous les objets séquentiels que nous avons vu.
for char in "YMCA":
print(char)
print() # Saut de ligne
= (1, 2, 3, 4, 5)
t for i in t:
print(i*9)
Y
M
C
A
9
18
27
36
45
La classe des objets itérables est cependant bien plus grande que les seuls objets séquentiels. Par exemple, on peut itérer sur les clés d’un dictionnaire, alors que l’on a vu dans un tutoriel précédent que ce n’était pas un objet séquentiel, puisqu’il n’y a pas de notion d’ordre dans un dictionnaire.
= {'cafe': '500g', 'lait': '1,5L', 'cereales': '1kg'}
inventaire for key in inventaire:
print(key)
print(inventaire[key])
print() # Saut de ligne
cafe
500g
lait
1,5L
cereales
1kg
range
En programmation, il est courant de vouloir itérer sur une suite d’entiers. Plutôt que de spécifier cette suite dans une liste, ce qui n’est pas très pratique si la suite est longue, on utilise pour ce faire la fonction range(n)
. Celle-ci crée un objet itérable qui contient tous les entiers compris entre \(0\) et \(n-1\), et qui peut être utilisé dans le cadre d’une boucle.
Regardons par exemple comment on peut très simplement afficher une table de multiplication à l’aide de cette fonction.
= 9
table
for i in range(11):
print(i, i*9)
0 0
1 9
2 18
3 27
4 36
5 45
6 54
7 63
8 72
9 81
10 90
On a vu qu’une boucle for
avait pour principe d’itérer sur les éléments d’un itérable. Cependant, dans le cas d’un objet séquentiel comme une liste, on peut parfois vouloir itérer sur les indices de l’objet, afin de pouvoir manipuler à la fois les indices et les éléments contenus dans l’objet. Dans ce cas, la fonction range
peut être utilisée en combinaison avec la fonction len
pour créer un objet itérable qui contient exactement les indices de la liste initiale.
= ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
gamme
for i in range(len(gamme)):
print("La note numéro " + str(i) + " de la gamme de do majeur est " + gamme[i])
La note numéro 0 de la gamme de do majeur est do
La note numéro 1 de la gamme de do majeur est re
La note numéro 2 de la gamme de do majeur est mi
La note numéro 3 de la gamme de do majeur est fa
La note numéro 4 de la gamme de do majeur est sol
La note numéro 5 de la gamme de do majeur est la
La note numéro 6 de la gamme de do majeur est si
Comme ce besoin est fréquent mais que le code ci-dessus n’est pas très lisible, il existe une fonction built-in de Python appelée enumerate
qui permet d’itérer à la fois sur les objets et les indices. Il est donc préférable d’utiliser cette syntaxe, plus claire, et qui permet d’éviter certaines erreurs.
La fonction enumerate
appliquée à un objet itérable renvoie un nouvel objet itérable qui contient l’ensemble des couples (indice, élément)
contenus dans l’objet, sous forme de tuples. Comme c’est un objet de type particulier – un générateur, que nous verrons dans un tutoriel plus avancé – il faut lui appliquer la fonction list
pour afficher son contenu.
list(enumerate(gamme))
[(0, 'do'), (1, 're'), (2, 'mi'), (3, 'fa'), (4, 'sol'), (5, 'la'), (6, 'si')]
Regardons comment réécrire la boucle précédente avec cette nouvelle syntaxe.
for i, note in enumerate(gamme):
print("La note numéro " + str(i) + " de la gamme de do majeur est " + note)
La note numéro 0 de la gamme de do majeur est do
La note numéro 1 de la gamme de do majeur est re
La note numéro 2 de la gamme de do majeur est mi
La note numéro 3 de la gamme de do majeur est fa
La note numéro 4 de la gamme de do majeur est sol
La note numéro 5 de la gamme de do majeur est la
La note numéro 6 de la gamme de do majeur est si
NB : pour faire l’assignation de variables dans l’instruction if
, on a utilisé une technique bien pratique que l’on avait déjà évoquée dans un exercice du tutoriel sur les listes et les tuples : le tuple unpacking. Illustrons le par un exemple :
= (1, 2, 3)
t = t
a, b, c print(a)
print(b)
print(c)
1
2
3
while
Les boucles while
fournissent une manière alternative de spécifier des procédures répétitives. L’idée n’est plus d’itérer sur un nombre d’objets fixé à l’avance, mais d’itérer tant qu’une condition (test logique) est remplie.
= 1
i while i <= 5:
print(i)
= i + 1 i
1
2
3
4
5
La différence essentielle avec la boucle for
est l’instruction : c’est désormais une instruction while
, suivie d’une condition (test), et comme toute instruction de :
.
Pour le reste, le principe est le même : l’instruction while
est suivi d’un bloc d’instructions, indenté d’un niveau, et qui s’exécute séquentiellement à chaque itération de la boucle.
Une différence essentielle des boucles while
par rapport aux boucles for
tient au critère d’arrêt. Dans une boucle for
, ce critère est clair : la boucle itère sur les éléments d’un objet itérable, nécessairement de taille finie. La boucle s’arrête donc lorsque chaque élément de l’itérable a été parcouru.
Dans une boucle while
au contraire, le critère d’arrêt est donné par une condition logique, c’est donc l’utilisateur qui doit fixer le critère d’arrêt. Dans l’exemple, pour que la boucle s’arrête, il faut que la condition i <= 5
devienne False
, c’est à dire que i
devienne strictement supérieur à \(5\). On s’est assuré de cela en initialisant i
à \(1\) avant le début de la boucle, puis en incrémentant i
d’une unité à chaque itération.
Que se passe-t-il si l’on oublie d’incrémenter i
? Le critère d’arrêt n’est jamais atteint, la boucle est donc infinie, et il faut utiliser le bouton “Stop” (carré noir) de Jupyter pour arrêter le programme en cours. Vérifions cela en incrémentant la mauvaise variable.
= 1
i = 1
j while i <= 5:
= j + 1 j
Ainsi, lorsqu’on pressent qu’une boucle while
met trop longtemps à tourner, il faut considérer l’hypothèse que l’on soit tombé dans une boucle infinie, et bien vérifier que le critère d’arrêt est atteignable.
break
Une manière alternative de spécifier un critère d’arrêt est d’utiliser l’instruction break
. Lorsque cette instruction est atteinte et exécutée, la boucle est immédiatement interrompue.
Illustrons son fonctionnement à l’aide d’un exemple. La première ligne crée une boucle infinie, dans la mesure où, par définition, True
est toujours évalué à True
. Le programme demande ensuite à l’utilisateur de taper un prénom, et ce infiniment jusqu’à que l’utilisateur tape le prénom attendu. Dans ce cas seulement, l’instruction break
est atteinte et la boucle s’arrête. Le message “Bienvenue print
n’est pas inclus dans la boucle.
= "Romain"
votre_prenom
while True:
print("Veuillez entrer votre prénom.")
= input()
prenom if prenom == votre_prenom:
break
print("Bienvenue " + votre_prenom)
Il est important de noter qu’une instruction break
ne met fin qu’à la boucle de niveau directement supérieur à elle. Dans le cas d’une boucle à plusieurs niveaux, il est tout à fait possible que les opérations continuent même lorsqu’une instruction break
a été atteinte.
Illustrons ce principe avec un exemple.
= 0
i while i <= 5:
for j in range(5):
if j == 2:
print("Break.")
break
+= 1 i
Break.
Break.
Break.
Break.
Break.
Break.
A chaque itération de la boucle while
, une boucle for
est lancée, qui atteint une instruction break
à la troisième itération (lorsque j
vaut 2). Cela a pour effet de mettre fin à la boucle for
, mais pas à la boucle while
, qui exécute la suite de ses instructions (l’incrémentation de i
d’une unité) avant de passer à l’itération suivante.
continue
L’instruction continue
permet de passer à l’itération suivante de la boucle.
Agrémentons l’exemple précédent pour illustrer son fonctionnement. Tant qu’un prénom différent de celui attendu est rentré, l’instruction continue
est évaluée, et le programme continue à demander un prénom à l’utilisateur. Lorsque le bon prénom est rentré, le programme demande à l’utilisateur de rentrer un mot de passe. Si le mot de passe est celui attendu, l’instruction break
est atteinte et exécutée, la boucle s’arrête. En cas de mauvais mot de passe en revanche, la boucle redémarre au début du bloc d’exécution, il faut donc de nouveau rentrer un prénom avant le mot de passe.
= "bob"
votre_prenom
while True:
print("Veuillez entrer votre prénom.")
= input()
prenom if prenom != votre_prenom:
continue
print("Veuillez entrer votre mot de passe.")
= input()
mdp if mdp == "lemotdepasse":
break
print("Bienvenue " + votre_prenom)
NB : le code ci-dessus à seulement valeur d’exemple. Comme on le verra dans un prochain tutoriel sur les bonnes pratiques de code, il ne faut jamais écrire de secrets (mots de passe, tokens..) en clair dans son code.
1/ Comment fonctionne une boucle for
?
2/ La variable d’itération définie lors d’une boucle for
persiste-t-elle en mémoire une fois la boucle terminée ?
3/ Que fait la fonction range
? Pourquoi est-elle particulièrement utile dans le cadre des boucles for
?
4/ Que fait la fonction enumerate
? Pourquoi est-elle particulièrement utile dans le cadre des boucles for
?
5/ Comment fonctionne une boucle while
?
6/ Quand s’arrête une boucle while
? En quoi cela diffère-t-il des boucles for
?
7/ Que fait l’instruction break
?
8/ Que fait l’instruction continue
?
1/ Une boucle for
définit une variable d’itération qui va parcourir chaque élément d’un objet itérable. A chaque itération, une série d’instructions est effectuée.
2/ Oui, et sa valeur finale est égale à la dernière valeur de l’objet itérable.
3/ La fonction range(n)
crée un objet itérable qui contient tous les entiers compris entre 0 et n-1. Elle est très utilisée comme itérable dans les boucles for
car elle permet d’itérer sur une séquence d’entiers sans avoir à mettre celle-ci dans une liste à la main.
4/ La fonction enumerate
appliquée à un objet itérable renvoie un nouvel objet itérable qui contient l’ensemble des couples (indice, élément) associés à l’objet initial, sous forme de tuples. Dans le cadre d’une boucle for
, elle permet d’itérer à la fois sur les éléments d’un itérable et sur les positions de ces éléments.
5/ Une boucle while
exécute une série d’instructions de manière répétée tant que la condition logique spécifiée évalue à True.
6/ Une boucle while
s’arrête dès lors que la condition logique spécifiée évalue à False. Si ce cas ne se produit jamais, une boucle while
peut donc être infinie. A l’inverse, une boucle for
peut être très longue mais jamais infinie, dans la mesure où elle s’arrête dès lors qu’elle a terminé de parcourir l’objet.
7/ L’instruction break
force la boucle de niveau directement supérieur à se terminer.
8/ L’instruction continue
force la boucle de niveau directement supérieur à passer à l’itération suivante.
while
Essayer de prédire ce que vont produire les boucles while
suivantes, et vérifiez vos résultats.
# 1.
= 0
i while i <= 10:
print(i)
# 2.
= 1
a while (a < 10):
+= 1
a if a == 5:
break
print("Condition d'arrêt atteinte.")
# 3.
while False:
print("hello world")
# 4.
while True:
print("hello world")
break
# 5.
while 5 >= 3:
continue
print("hello world")
# Testez votre réponse dans cette cellule
Source : python.sdv.univ-paris-diderot.fr
Afin de visualiser l’importance de l’indentation dans les blocs d’instruction, essayez de prédire ce que vont respectivement retourner les deux programmes suivants. Lequel a l’effet attendu ?
= [4, 5, 6]
nombres for nb in nombres:
if nb == 5:
print("Le test est vrai")
print(f"car la variable nb vaut {nb}")
Le test est vrai
car la variable nb vaut 5
= [4, 5, 6]
nombres for nb in nombres:
if nb == 5:
print("Le test est vrai")
print(f"car la variable nb vaut {nb}")
car la variable nb vaut 4
Le test est vrai
car la variable nb vaut 5
car la variable nb vaut 6
# Testez votre réponse dans cette cellule
print
n’est pas correctement indenté. En conséquence, il s’exécute à chaque itération et non pas juste lorsque nb == 5
.
for
en boucle while
Réécrivez la boucle for
suivante à l’aide d’une boucle while
.
= ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
gamme
for i, note in enumerate(gamme):
print("La note numéro " + str(i) + " de la gamme de do majeur est " + note)
La note numéro 0 de la gamme de do majeur est do
La note numéro 1 de la gamme de do majeur est re
La note numéro 2 de la gamme de do majeur est mi
La note numéro 3 de la gamme de do majeur est fa
La note numéro 4 de la gamme de do majeur est sol
La note numéro 5 de la gamme de do majeur est la
La note numéro 6 de la gamme de do majeur est si
# Testez votre réponse dans cette cellule
= ['do', 're', 'mi', 'fa', 'sol', 'la', 'si']
gamme
= 0
i while i <= (len(gamme) - 1):
# On soustrait 1 à la longueur de `gamme` car l'index maximal est 6
print("La note numéro " + str(i) + " de la gamme de do majeur est " + gamme[i])
+= 1 i
Soit un entier cible n_cible
et une liste d’entiers l
tels que définis dans la cellule suivante. A l’aide d’une boucle for
et de la fonction enumerate
:
vérifier si l’entier cible est présent dans la liste l
.
si oui, afficher le message ‘Le nombre n_cible
est à la position i
de la liste’, et mettre fin à la boucle.
= 78
n_cible
= [12, 98, 65, 39, 78, 55, 119, 27, 33] l
# Testez votre réponse dans cette cellule
= 78
n_cible
= [12, 98, 65, 39, 78, 55, 119, 27, 33]
l
for i, n in enumerate(l):
if n == n_cible:
print("Le nombre " + str(n) + " est à la position " + str(i) + " de la liste.")
break
# NB : version plus efficiente sans boucle
if n_cible in l:
= l.index(n_cible)
pos print("Le nombre " + str(n_cible) + " est à la position " + str(pos) + " de la liste.")
La suite de Fibonacci se définit de la manière suivante :
les deux premiers nombres sont 0 et 1
chaque autre nombre de la suite s’obtient en additionnant les deux nombres qui le précèdent
Ecrire un programme permettant de calculer les \(n\) premiers termes de la suite à l’aide d’une boucle for
.
# Testez votre réponse dans cette cellule
= 20
n_termes = 0
num1 = 1
num2
for i in range(n_termes):
print(num1)
= num1 + num2
num3 = num2
num1 = num3 num2
A l’aide de deux boucles for
imbriquées, construire un dictionnaire tables
permettant de réaliser les tables de multiplication jusqu’à la table de 12. Requêtez votre dictionnaire pour vérifier sa pertinence.
Voici quelques exemples de requête que doit renvoyer votre dictionnaire :
tables[2][3] -> 6
tables[9][5] -> 45
tables[12][7] -> 84
# Testez votre réponse dans cette cellule
= {}
tables
for i in range(13):
= {}
tables[i] for j in range(13):
= i*j
tables[i][j]
print(tables[2][3])
print(tables[9][5])
print(tables[12][7])
Calculer le minimum et le maximum de la série de valeurs suivantes, sans utiliser les fonctions min
et max
de Python.
x = [8, 18, 6, 0, 15, 17.5, 9, 1]
# Testez votre réponse dans cette cellule
= [8, 18, 6, 0, 15, 17.5, 9, 1]
x
= x[0]
current_min = x[0]
current_max for n in x[1:]:
if n <= current_min:
= n
current_min if n >= current_max:
= n
current_max
print(current_min == min(x))
print(current_max == max(x))
Calculer la moyenne et la variance de la série de valeurs suivantes, sans utiliser des fonctions déjà codées :
x = [8, 18, 6, 0, 15, 17.5, 9, 1]
Pour rappel, les formules sont :
moyenne : \[\bar{x} = {\frac {1}{n}}\sum_{i=1}^{n}x_{i}\]
variance : \[\sigma^2 = {\frac {1}{n}}\sum_{i=1}^{n} (x_{i}-\bar{x})^2\]
NB :
n à la puissance k s’écrit en Python n**k
en pratique, il ne faut surtout pas essayer de recoder soi-même ce genre de fonctions, mais utiliser des fonctions issues de packages adaptés, comme numpy
.
# Testez votre réponse dans cette cellule
= [8, 18, 6, 0, 15, 17.5, 9, 1]
x = len(x)
n
= 0
somme_moy for x_i in x:
+= x_i
somme_moy = somme_moy / n
moyenne
= 0
somme_var for x_i in x:
+= (x_i - moyenne)**2
somme_var = somme_var / n
variance
print(moyenne)
print(variance)
# Vérification avec les fonctions du package numpy
import numpy as np
print(np.mean(x))
print(np.var(x))
range
Nous avons vu plus haut l’usage basique de la fonction range
: range(n)
crée un objet itérable qui contient l’ensemble des entiers de \(0\) à \(n-1\). Les usages possibles de cette fonction sont cependant plus complets, et parfois utiles dans le cadre de problèmes précis.
La syntaxe complète de la fonction est range(start, stop, step)
où :
start
est l’entier à partir duquel commence la séquence d’entiers
stop
est l’entier avant lequel se termine la séquence d’entiers
step
est le pas, i.e. la valeur de l’incrément entre chaque entier de la séquence.
Seul le paramètre stop
est obligatoire, c’est celui qui est utilisé lorsqu’on appelle range(n)
.
En utilisant la fonction range
, afficher :
l’ensemble des entiers de 0 à 10 (10 exclu)
l’ensemble des entiers de 10 à 20 (20 inclus)
l’ensemble des nombres pairs compris entre 30 et 40 (40 inclus)
l’ensemble des multiples de 10 entre 1 et 100 (100 exclu)
l’ensemble des entiers de 10 à 20 (20 inclus), dans l’ordre inverse (de 20 à 10)
# Testez votre réponse dans cette cellule
print(list(range(10)))
print(list(range(10, 21)))
print(list(range(30, 41, 2)))
print(list(range(10, 100, 10)))
print(list(range(20, 9, -1)))
Dans le précédent tutoriel, nous avons codé un jeu du juste prix. Mais il était un peu limité, puisqu’il fallait réexécuter le code à chaque étape du jeu. A l’aide de boucles, réécrivez le jeu de manière complètement automatique.
Rappel des règles :
En utilisant input
et les instructions if
, elif
et else
, coder le programme suivant :
demander une valeur à l’utilisateur, qui sera stockée dans une variable p
si p
est strictement inférieur à \(15\), imprimer (avec la fonction print
) le message “trop bas !”.
si p
est strictement supérieur à \(15\), imprimer le message “trop haut !”.
si p
est égal à \(15\), imprimer le message “dans le mille !”
Attention, input
renvoie par défaut une chaîne de caractère. Il faut donc convertir la valeur de p
au format entier (via la fonction int
) pour que le jeu fonctionne.
# Testez votre réponse dans cette cellule
= 15
juste_prix
while True:
print("Proposer un nombre entre 1 et 50.")
= input()
p = int(p)
p if p < juste_prix:
print("trop bas !")
elif p > juste_prix:
print("trop haut !")
else:
break
print("dans le mille !")