Les boucles

Un petit problème....

Soit une situation où l'on voudrait afficher les multiples croissants de 2 jusqu'à 20 ( par exemple...).
Comment faudrait-il écrire un tel programme ?

ALGORITHME
valeur ← 2
valeur ← valeur + 2
afficher valeur
valeur ← valeur + 2
afficher valeur
valeur ← valeur + 2
afficher valeur
valeur ← valeur + 2
afficher valeur
........... et ceci 20 fois.....
REPONSE

valeur = 2
print( valeur ) # affiche 2
valeur = valeur + 2
print( valeur ) # affiche 4
valeur = valeur + 2
print( valeur ) # affiche 6
valeur = valeur + 2
print( valeur ) # affiche 8
valeur = valeur + 2
print( valeur ) # affiche 10
valeur = valeur + 2
print( valeur ) # affiche 12
valeur = valeur + 2
print( valeur ) # affiche 14
valeur = valeur + 2
print( valeur ) # affiche 16
valeur = valeur + 2
print( valeur ) # affiche 18
valeur = valeur + 2
print( valeur ) # affiche 20
					

Pas vraiment élégant, n'est-ce pas ? Il y a sûrement plus efficace que d'écrire 10 fois la même chose !

Très souvent, on a effectivement ainsi besoin de répéter plusieurs fois les mêmes séquences d'instructions
D'où l'existence de structures de boucles qui font partie, comme l'instruction if, des structures de contrôle de flux.

En Python, deux structures de boucle existent :

La boucle for ( boucle inconditionnelle )

Vous avez en fait déjà utilisé ce type de structure, mais sous une forme un peu différente, avec la boucle for ... in ... qui permet de parcourir un objet itérable comme une chaîne de caractères.

Structure


for compteur in range( intervalle de variation du compteur ) :
	Instruction(s) à exécuter dans la boucle
	..............
	..............
			

Principe

Par ske — Travail personnel,
Domaine public,
wikipedia.fr

Cette boucle "tourne" en exécutant à chaque "tour" la (ou des) instruction(s) du bloc.

La variable compteur de boucle ( nommée ici compteur, mais on peut bien entendu utiliser n'importe quel nom..) permet de compter le nombre de "tours" de la boucle; elle est automatiquement incrémentée ( ou décrémentée ! ) d'une certaine valeur ( = le pas de la boucle ) à la fin de chaque "tour"; la boucle "tournera" alors tant que la valeur du compteur se trouve dans l'intervalle de variation indiqué.

Il existe plusieurs façons d'indiquer les bornes de cet intervalle :


for compteur in range( N ) :
					

⇨ intervalle de 0 jusqu’à N - 1 avec un pas de variation de 1 ( pour N = 10, le compteur varie donc de 0 à 9 par pas de 1, soit 10 "tours" )


for compteur in range( N1 , N2 ) :
					

⇨ intervalle de N1 jusqu'à N2 - 1 avec un pas de variation de 1 ( pour l'exemple précédent, on aurait : N1 = 0 et N2 = 10 )


for compteur in range( N1 , N2 , pas ) :
					

⇨ intervalle de N1 jusqu'à N2 - 1 avec un pas de variation quelconque

On constate donc que l'intervalle va toujours de la borne inférieure à la borne supérieure -1 avec un pas par défaut de 1.

Exemples d'utilisation


for i in range( 4 ) :
			
⇨ le compteur i prendra les valeurs : 0, 1, 2, 3 soit 4 "tours" de boucle.


for i in range( 3 , 10 ) :
			
⇨ le compteur i prendra les valeurs : 3, 4, 5, 6, 7, 8, 9 soit 7 "tours" de boucle.


for i in range( 10 , 2 , -2 ) :
			
⇨ le compteur i prendra les valeurs : 10, 8, 6, 4 ( le pas est de -2 ) soit 4 "tours" de boucle.

L'exemple d'introduction du chapitre deviendrait alors :


valeur = 2
for i in range( 10 ) :
	print( valeur )
	valeur = valeur + 2
			

⇨ 4 lignes au lieu de 18 !!

Vous remarquez que les instructions à exécuter dans la boucle appartiennent donc au même bloc logique, elles sont donc indentées de la même façon par rapport au mot clé for.

Utilisation de la variable compteur à l'intérieur de la boucle

A l'intérieur de la boucle, on aura souvent besoin d'utiliser la valeur de la variable compteur pour réaliser certaines opérations.

Par exemple, pour afficher tous les multiples d'un certain nombre, on écrira une instruction qui, à chaque tour de boucle, multipliera ce nombre par la valeur du compteur, de façon à obtenir tous les multiples :


nombre = 2
for i in range(10):
	print(nombre, "x", i, "=", nombre*i)
			

Une boucle dans une boucle : les boucles imbriquées

On a aussi parfois besoin de la structure suivante :


for i in range(3):
	for j in range(4):
		print("i =", i, "j =", j)
			

En étudiant l'indentation, on constate la présence dans ce code :

Étudiiez l’exécution de ce code :


	i = 0 j = 0
	i = 0 j = 1
	i = 0 j = 2
	i = 0 j = 3
	i = 1 j = 0
	i = 1 j = 1
	i = 1 j = 2
	i = 1 j = 3
	i = 2 j = 0
	i = 2 j = 1
	i = 2 j = 2
	i = 2 j = 3
			

Voila ce qu'il se passe :

  1. la variable i prend la valeur i = 0
    • la variable j prend successivement les valeurs j = 0, 1, 2 et 3; pendant ce temps, i n'a pas changé de valeur et vaut toujours i = 0
    • à chaque tour de la boucle j, l'instruction print() s'éxécute : on obtient donc l'affichage des lignes 2 à 5 ci-dessus.
  2. quand l'éxécution de la boucle j est terminée, on sort de celle-ci : on commence donc le deuxième tour de la boucle i, qui prend alors la valeur i = 1
    • j reprend alors à nouveau successivement les les valeurs j = 0, 1, 2 et 3 alors que i garde toujours sa valeur i = 1
    • on obtient l'affichage des lignes 6 à 9
  3. et enfin, le dernier tour de la boucle i pour i = 2, et l'éxécution à nouveau de la boucle j, donne l'affichage des lignes 10 à 13.

→ la boucle j a donc été éxécutée autant de fois que de tours de la boucle i.

Cette structure particulière où "une boucle tourne dans une autre boucle" est appelée boucles imbriquées; elle n'est pas évidente à comprendre, étudiez-la bien : elle sert dans de nombreuses situations ( vous verrez un premier exemple ci-dessous ), notamment dès que l'on a à parcourir un objet en deux dimensions comme les pixels d'une image, ou une liste de listes ( vous verrez cela plus tard ).

La boucle while ( boucle conditionnelle )

Structure


while ( condition ) :
	Instruction(s)
	.......
			

Principe

Cette boucle « tourne » tant que ( = while ) la condition évaluée est vraie, autrement dit jusqu'à ce qu'elle devienne fausse...
Bien remarquer que cette condition est évaluée au début de chaque "tour".
Dès que la condition devient fausse, le programme "sort" donc de la boucle et passe aux instructions suivantes...

La condition est une expression, plus ou moins complexe, à évaluer à l'aide d'opérateurs de comparaison.

Ce sont les mêmes que ceux rencontrées au chapitre précédent :

Opérateur Signification Commentaire
== égal à Bien noter qu'il s'agit là-aussi d'un DOUBLE SIGNE ÉGAL...
!= différent de
> supérieur à
< inférieur à
>= supérieur ou égal à
<= inférieur ou égal à
in est dans
not in n'est pas dans

La (ou les) instruction(s) constituent le bloc qui sera exécuté à chaque "tour" de boucle ; elles sont donc indentées d'un même retrait par rapport à l'instruction "parente" ( ici, l'instruction while ) pour indiquer à Python qu'il s'agit du même bloc logique.

Exemple d'utilisation

Pour l'exemple d'introduction :

i = 0
valeur = 2

while ( i < 10 ) :
	print( valeur )
	valeur = valeur + 2
	i +=1
			

Ce mode de fonctionnement sous-entend que quelque chose doit, dans le bloc d'instructions, agir sur la variable testée dans la condition évaluée, sinon la condition ne deviendra jamais fausse, et la boucle peut alors ne jamais s'arrêter de "tourner" !!!

ATTENTION donc au risque de boucle infinie !!

Et alors : faut-il utiliser la boucle for ou la boucle while ???

Dans certains cas....les deux !!

On peut très bien par exemple réécrire les exemples précédents avec une boucle while au lieu du for :

Boucle for Boucle while

for i  in range( 4 ) :

	Instruction 1

	Instruction 2

	......
						

i = 0  # définition du compteur de boucle

while ( i < 4 ) :

	Instruction 1

	Instruction 2

	......

	i = i + 1 # Incrémentation du compteur
						

for i  in range( 3 , 10 ) :

	Instruction 1

	Instruction 2

	......
						

i = 3

while ( i < 10 ) :

	Instruction 1

	Instruction 2

	......

	i += 1 # Autre façon d'écrire l'incrémentation
						

for i  in range( 10 , 2 , -2 ) :

	Instruction 1

	Instruction 2

	......
						

i = 10

while ( i > 2 ) :

	Instruction 1

	Instruction 2

	......

	i -= 2  # il s'agit ici d'une décrémentation

						

On constate cependant qu'avec la boucle while, le code est plus "lourd", d'autant plus qu'il faut soi-même gérer l'évolution du compteur ( ce qui est "automatique" avec une boucle for ), avec les risques de "boucle infinie" que cela entraîne...; l'utilisation de la boucle conditionnelle n'est donc pas judicieuse dans ces exemples...

Quel est son intérêt alors ? Et bien, le nombre de "tours" d'une boucle while n'est pas fixé à l'avance, au contraire de la boucle for, dont le nombre de tours est fixé à son début.

Dans quel cas cela est-il utile ? Par exemple, l'entrée d'un mot de passe par un utilisateur : tant que l'entrée n'est pas la bonne, on redemande le mot de passe...et cela peut durer un nombre de fois indeterminé à l'avance !!


motDePasse = 'sdhfj7$ff'

entree = ''  # initialisation de l'entrée utilisateur à "vide"

while ( entree != motDePasse ) :

	entree = input('Entrez le mot de passe :')

print('Accès autorisé')
			

En conclusion, on utilisera :

  • une boucle for quand on connaît le nombre de "tours" à effectuer.
  • une boucle while quand on ne le connaît pas.

Exercices

Boucles for

Combien de fois les boucles suivantes seront-elles exécutées ?


for i  in range( 6 ) :

	Instruction 1

	Instruction 2

	......
			
REPONSE
La variable i va prendre les valeurs : 0, 1, 2, 3, 4 et 5 → 6 "tours" en tout.

for i  in range( 5 , -1 , -1 ) :

	Instruction 1

	Instruction 2

	......
			
REPONSE
La variable i va prendre les valeurs : 5, 4, 3, 2, 1, et 0 → 6 "tours" en tout.

Boucle while

Combien de fois les boucles suivantes sont-elles exécutées ?


compteur = 1

while ( compteur < 8 ) :

	compteur+=1
			
REPONSE
La variable va prendre les valeurs : 1, 2, 3, 4, 5, 6 et 7 → 7 "tours".

compteur = 0

while ( compteur < 6 ) :

	compteur+=1
			
REPONSE
La variable va prendre les valeurs : 0, 1, 2, 3, 4, et 5 → 6 "tours".

compteur = 15

while ( compteur < 15 ) :

	compteur+=1
			
REPONSE
La condition n'est jamais vraie : la boucle ne tournera donc d'aucun "tour" !...

Que peut-on dire de la boucle ci-dessous, destinée à afficher les puissances de 2 successives ?


compteur = 0

a = 1

while ( compteur < 10 ) :

	print ( a )

	a = a * 2
			
REPONSE
Rien ne modifie la variable compteur dans la boucle : la condition est donc toujours vraie ⇒ boucle infinie !

Corriger et réécrire ce programme plus judicieusement.

REPONSE

compteur = 0 # une seule variable pour tout faire...

while ( compteur < 10 ) :

	print ( 2 ** compteur )

	compteur += 1
					

QCM d'entraînement

Que s'affiche-t-il à la fin de l'exécution de chacun des scripts suivants ?

Applications

Pour ces applications, boucle for ou while, à vous de choisir la mieux adaptée selon la situation...

L'écho (exercice_A15.py)

Écrire une boucle qui affiche 20 fois le mot "Echo".



				

Écrire une boucle qui affiche la table de multiplication de 3 (exercice_A16.py)

				
	1 3 6 9 12 15 18 21 24 27 30
				
			

Une contrainte : utiliser la valeur du compteur elle-même pour effectuer le calcul des multiples.

Pour afficher sur une même ligne avec la fonction print, utiliser la syntaxe suivante :

print( affichage , end = ' ') # un espace entre les guillemets
				
Pour revenir à la ligne ( ou également pour en sauter une ) :

print()
				


				

Compte à rebours (exercice_A17.py)

Écrire une boucle qui affiche un compte à rebours de 20 à 0 INCLUS

				
	20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
				
			


				

Écrire un programme qui affiche les unes à la suite des autres les tables de multiplication de 1,2,....,10. (exercice_A18.py)

				
	1 2 3 4 5 6 7 8 9 10
	2 4 6 8 10 12 14 16 18 20
	3 6 9 12 15 18 21 24 27 30
	4 8 12 16 20 24 28 32 36 40
	5 10 15 20 25 30 35 40 45 50
	6 12 18 24 30 36 42 48 54 60
	7 14 21 28 35 42 49 56 63 70
	8 16 24 32 40 48 56 64 72 80
	9 18 27 36 45 54 63 72 81 90
	10 20 30 40 50 60 70 80 90 100
				
			
AIDE 1
Il faut répéter 10 fois la boucle de l'exercice 2 en changeant à chaque fois la valeur du nombre dont on veut la table.


				

Le calendrier (exercice_A19.py)

Écrire un programme qui permette d'afficher un calendrier pour un mois de 28 jours avec chaque semaine sur une ligne différente.

				
	1 2 3 4 5 6 7
	8 9 10 11 12 13 14
	15 16 17 18 19 20 21
	22 23 24 25 26 27 28
				
			


				

Le jeu du nombre à deviner ( Utilisation des boucles ET des conditions ) (exercice_A20.py)

Le but du jeu : le programme tire un nombre entier au hasard ( entre 1 et 100 par exemple ) ; le joueur doit essayer de deviner le nombre, et doit faire des propositions. Chaque proposition est évaluée, et le programme doit afficher " Trop grand", "Trop petit", ou "Gagné !" après chaque proposition.
Le programme doit "tourner" tant que le joueur n'a pas donné la bonne réponse...

Il sera nécessaire d’utiliser la fonction randint ( tirage aléatoire d'un nombre entier ) qu'il faudra importer depuis le module random.
On pourra n'importer que cette fonction ou bien le module entier...

Pour utiliser ensuite la fonction dans le programme :


	nombre = randint( borne1 , borne2 )
				
→ renvoie un entier dans une plage entre deux bornes ( incluses ).
AIDE

Pour importer la fonction tirage aléatoire d'entier :


from random import randint
						

Pour les bornes sur le nombre à tirer au hasard entre 1 et 100 :


n = randint( 1 , 100 )
						
ALGORITHME
							nombre ← tirage au hasard entier entre 1 et 100
							entree ← 0

							tant que entree != nombre :
								entree ← entree utilisateur
								si entree > nombre
									alors afficher "Trop grand !"
								si entree < nombre
									alors afficher "Trop petit !"
sinon afficher "Bravo !" fin si fin tant que