7 Boucles

Quand on doit répéter plusieurs fois la même opération, pour un nombre déterminé de fois ou tant qu’une condition est vérifiée (ou tant qu’elle n’est pas vérifiée), on peut utiliser des boucles, ce qui est bien moins pénible que d’évaluer à la main ou à coups de copier/coller la même instruction.

Nous allons aborder deux types de boucles dans ce chapitre :

  • celles pour lesquelles nous ne savons pas a priori le nombre d’itérations (le nombre de répétitions) à effectuer : les boucles while()
  • celles pour lesquelles nous savons a priori combien d’itérations sont nécessaires : les boucles for()

Il est possible d’arrêter une boucle for() avant un nombre d’itérations prédéfini ; dans le même esprit, il est possible d’utiliser une boucle while() en sachant d’avance le nombre d’itérations à effectuer.

7.1 Boucles avec while()

Le principe d’une boucle while() est que les instructions à l’intérieur de la boucle seront répétées tant qu’une condition est respectée. L’idée est de faire dépendre cette condition d’un ou plusieurs objets qui seront modifiés au cours des itérations (sans cela, la boucle tournerait à l’infini).

La syntaxe est la suivante :

while condition:
  instructions

Comme pour les instructions conditionnelles (c.f. Section 6), les instructions sont placées à l’intérieur d’un bloc.

Regardons un exemple de boucle while() :

x = 100
while x/3 > 1:
  print(x/3)
  x = x/3
## 33.333333333333336
## 11.111111111111112
## 3.703703703703704
## 1.234567901234568
print(x/3>1)
## False
print(x/3)
## 0.41152263374485604

Dans cette boucle, à chaque itération, la valeur de x divisé par 3 est affichée, puis la valeur de x est remplacée par le tiers de sa valeur courante. Cette opération est répétée tant que l’expression x/3 > 1 retourne True.

7.2 Boucles avec for()

Quand on connaît le nombre d’itérations à l’avance, on pourra utiliser une boucle for(). La syntaxe est la suivante :

for objet in valeurs_possibles:
  instructions

avec objet le nom d’une variable locale à la fonction for(), valeurs_possibles un objet comprenant \(n\) éléments définissant les valeurs que prendra objet pour chacun des \(n\) tours, et instructions les instructions qui seront exécutées à chaque itération.

Nous allons, dans l’exemple qui suit, calculer le carré des \(n\) premiers entiers. Les valeurs que vont prendre notre variable objet (que nous allons appeler i) seront les entiers de 1 à \(n\). Pour obtenir une séquence d’entiers en Python, on peut utiliser la fonction range(), qui prend les paramètres suivants :

  • start : (optionnel, par défaut, 0) valeur de début pour la séquence (inclue) ;
  • stop : valeur de fin de la séquence (non inclue) ;
  • step : (optionnel, par défaut 1) le pas.

Avant de calculer la suite des \(n\) premiers carrés, regardons un exemple de fonctionnement de la fonction range() :

print(list(range(0, 4))) # Les entiers de 0 à 3
## [0, 1, 2, 3]
print(list(range(4))) # Les entiers de 0 à 3
## [0, 1, 2, 3]
print(list(range(2, 10))) # Les entiers de 2 à 9
## [2, 3, 4, 5, 6, 7, 8, 9]
print(list(range(2, 10, 3))) # Les entiers de 2 à 9 par pas de 3
## [2, 5, 8]

Aussi, pour afficher la suite des \(10\) premiers carrés :

message = "Le carré de {} est {}" 
n=10
for i in range(0, n+1):
  print(message.format(i,i**2))
## Le carré de 0 est 0
## Le carré de 1 est 1
## Le carré de 2 est 4
## Le carré de 3 est 9
## Le carré de 4 est 16
## Le carré de 5 est 25
## Le carré de 6 est 36
## Le carré de 7 est 49
## Le carré de 8 est 64
## Le carré de 9 est 81
## Le carré de 10 est 100

Lors de la première itération, i vaut 0. Lors de la seconde, i vaut 1. Lors de la troisième, i vaut 2, etc.

Si on veut stocker le résultat dans une liste :

n=10
n_entiers_carres = []
for i in range(0, n+1):
  n_entiers_carres.append(i**2)
  
print(n_entiers_carres)
## [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Il n’est pas obligatoire d’utiliser la fonction range() dans une boucle for(), on peut définir les valeurs “à la main” :

message = "Le carré de {} est {}"
for i in [0, 1, 2, 8, 9, 10]:
  print(message.format(i,i**2))
## Le carré de 0 est 0
## Le carré de 1 est 1
## Le carré de 2 est 4
## Le carré de 8 est 64
## Le carré de 9 est 81
## Le carré de 10 est 100

Dans le même esprit, il n’est pas obligatoire d’itérer sur des valeurs numériques :

message = "Il y a {} lettre(s) dans le prénom {}"
for prenom in ["Pascaline", "Gauthier", "Xuan", "Jimmy"]:
  print(message.format(len(prenom), prenom))
## Il y a 9 lettre(s) dans le prénom Pascaline
## Il y a 8 lettre(s) dans le prénom Gauthier
## Il y a 4 lettre(s) dans le prénom Xuan
## Il y a 5 lettre(s) dans le prénom Jimmy

Rien n’empêche de faire des boucles à l’intérieur de boucles :

message = "i vaut {} et j vaut {}"
for i in range(0,3):
    for j in range(0,3):
        print(message.format(i, j))
## i vaut 0 et j vaut 0
## i vaut 0 et j vaut 1
## i vaut 0 et j vaut 2
## i vaut 1 et j vaut 0
## i vaut 1 et j vaut 1
## i vaut 1 et j vaut 2
## i vaut 2 et j vaut 0
## i vaut 2 et j vaut 1
## i vaut 2 et j vaut 2

Comme on peut le constater, l’itération se fait pour chaque valeur de i, et pour chacune de ces valeurs, une seconde itération est effectuée sur les valeurs de j.

On utilise souvent les lettres i et j pour désigner un compteur dans une boucle for(), mais ce n’est évidemment pas une obligation.

Dans une boucle, si on désire incrémenter un comteur, on peut utiliser le symbole += plutôt que d’écrire compteur = compteur + ... :

message = "Nouvelle valeur pour j : {}"
j = 10
for i in range(0, 4):
  j += 5
  print(message.format(j))
  
## Nouvelle valeur pour j : 15
## Nouvelle valeur pour j : 20
## Nouvelle valeur pour j : 25
## Nouvelle valeur pour j : 30
print(j)
## 30

7.3 Exercice

  1. Rédiger un programme très naïf visant à déterminer si un nombre est premier ou non. Pour ce faire :

    1. définir une variable nombre contenant un entier naturel de votre choix (pas trop grand),
    2. à l’aide d’une boucle, vérifier si chaque entier jusqu’à la racine carrée de votre nombre, est un diviseur de votre nombre (s’arrêter si jamais c’est le cas)
    3. en sortie de boucle, écrire une instruction conditionnelle indiquant si le nombre est premier ou non.
  2. Choisir un nombre mystère entre 1 et 100, et le stocker dans un objet que l’on nommera nombre_mystere. Ensuite, créer une boucle qui à chaque itération effectue un tirage aléatoire d’un entier compris entre 1 et 100. Tant que le nombre tiré est différent du nombre mystère, la boucle doit continuer. À la sortie de la boucle, une variable que l’on appellera nb_tirages contiendra le nombre de tirages réalisés pour obtenir le nombre mystère.

Note : pour tirer un nombre aléatoirement entre 1 et 100, on peut utiliser la méthode randint() du module random).

  1. Parcourir les entiers de 1 à 20 à l’aide d’une boucle for en affichant dans la console à chaque itération si le nombre courant est pair.
  2. Utiliser une boucle for() pour reprouire la suite de Fibonacci jusqu’à son dixième terme (la séquence \(F_n\) est définie par la relation de récurrence suivante : \(F_n = F_{n-1} + F_{n-2}\) ; les valeurs initiales sont \(F_0 = 0\) et \(F_1 = 1\)).