Aller au contenu principal

Conditions et boucles

Jusqu'ici, les programmes se lisaient de haut en bas, ligne après ligne, toujours dans le même ordre. Ce chapitre change cela : le programme va se mettre à décider et à répéter.

On a déjà vu ces idées en algorithmique, sous la forme « Si / Alors / Sinon » et « Tant que ». Python reprend exactement la même logique. C'est le chapitre le plus important du cours : ces deux mécanismes sont dans absolument tous les programmes qu'on écrira.

Ce qu'on va apprendre

  • Prendre une décision avec if, elif et else.
  • Comprendre pourquoi une suite de if ne fait pas la même chose qu'un elif.
  • Répéter avec for et avec while, et savoir lequel choisir.
  • Éviter les trois pièges classiques : = au lieu de ==, or mal écrit, boucle infinie.

La première décision

Un programme qui décide, cela ressemble à ceci. Exécuter, puis change la valeur de age.

main.py
Sortie
>_ Prêt à exécuter…

Deux lignes s'affichent seulement quand la condition est vraie, une troisième s'affiche toujours. Regardons bien pourquoi : les deux premières sont décalées vers la droite, la dernière non.

L'indentation, la règle d'or

Définition

L'indentation est le décalage d'une ligne vers la droite. En Python, elle n'est pas décorative : c'est elle, et elle seule, qui dit quelles lignes appartiennent au bloc.

Là où d'autres langages emploient des accolades, Python emploie l'espace. La convention est de quatre espaces par niveau. Ce qui est décalé sous le if ne s'exécute que si la condition est vraie ; ce qui revient à gauche s'exécute dans tous les cas.

À faire. Dans le bloc précédent, décale print("Fin du programme.") de quatre espaces vers la droite, mets age = 15, et relance. La ligne ne s'affiche plus : elle est devenue une ligne du if.

Le bloc suivant est faux exprès : l'indentation manque.

main.py
Sortie
>_ Prêt à exécuter…

IndentationError: expected an indented block. Traduction : Python a lu les deux points, il attend donc un bloc décalé, et il n'en trouve pas.

Choisir entre plusieurs cas

else couvre tout ce que le if n'a pas pris. elif, contraction de « else if », ajoute un cas intermédiaire.

main.py
Sortie
>_ Prêt à exécuter…

Python teste dans l'ordre et s'arrête à la première condition vraie. Les suivantes ne sont même pas évaluées.

Une suite de if ne fait pas la même chose qu'un elif
C'est l'erreur la plus coûteuse du chapitre, parce qu'elle ne provoque aucun message : le programme tourne, il donne simplement un résultat faux.

Exécutons ce bloc, qui attribue une mention à une note de 15.

main.py
Sortie
>_ Prêt à exécuter…

Deux lignes s'affichent. Les trois if sont indépendants : chacun est évalué, et les deux premiers sont vrais. Ce n'est pas ce qu'on voulait.

À faire. Remplacer les deuxième et troisième if par des elif, puis inverse l'ordre en mettant note >= 16 en premier. Relance : une seule mention s'affiche, la bonne. Avec elif, l'ordre décide de tout.

Comparer

OpérateurSensExempleRésultat
==égal à5 == 5True
!=différent de3 != 4True
< <=inférieur, inférieur ou égal3 <= 3True
> >=supérieur, supérieur ou égal8 >= 9False

Un test renvoie toujours un booléen, True ou False. On peut l'afficher directement, c'est un bon moyen de vérifier une condition compliquée avant de la mettre dans un if.

main.py
Sortie
>_ Prêt à exécuter…

Le bloc suivant est faux exprès : il confond affectation et comparaison.

main.py
Sortie
>_ Prêt à exécuter…

SyntaxError: invalid syntax. Rappelons-nous le chapitre 2 : = colle une étiquette, c'est une action. == compare, c'est une question. Dans un if, on pose une question.

Combiner plusieurs conditions

and exige que les deux soient vraies, or qu'au moins une le soit, not inverse.

main.py
Sortie
>_ Prêt à exécuter…
« si le choix est 1 ou 2 » ne se traduit pas mot à mot
En français, on dit « si le choix vaut 1 ou 2 ». Traduit littéralement, cela donne if choix == 1 or 2:, et cette condition est toujours vraie, quelle que soit la valeur de choix.
Python lit en effet (choix == 1) or (2). Or le nombre 2 n'est pas nul, donc il vaut True, comme on l'a vu au chapitre 2 avec bool(2). Un or dont un côté est toujours vrai est toujours vrai.
Il faut répéter la variable de chaque côté : if choix == 1 or choix == 2:

Le vérifier soi-même : le premier test devrait être faux, et pourtant.

main.py
Sortie
>_ Prêt à exécuter…

Il existe une écriture plus courte et plus sûre, qu'on peut employer dès maintenant : if choix in (1, 2):.

Répéter un nombre connu de fois : for

Définition

La boucle for répète un bloc pour chaque élément d'une suite de valeurs. On l'emploie quand on sait, avant de commencer, sur quoi on va boucler.

main.py
Sortie
>_ Prêt à exécuter…

La variable i n'est pas la boucle : c'est une étiquette que Python décolle et recolle sur une nouvelle valeur à chaque tour, exactement comme au chapitre 2. Après la boucle, elle garde la dernière valeur prise.

main.py
Sortie
>_ Prêt à exécuter…

On boucle aussi directement sur une suite de valeurs, sans passer par des numéros.

main.py
Sortie
>_ Prêt à exécuter…

Les crochets créent une liste, une suite de valeurs rangées dans l'ordre. Le chapitre suivant lui est entièrement consacré ; ici, il suffit de savoir que for la parcourt du premier au dernier élément.

range(), et sa borne qui surprend

range(debut, fin, pas) engendre des entiers : debut inclus, fin exclue, pas valant 1 par défaut.

main.py
Sortie
>_ Prêt à exécuter…
La fin est exclue, toujours
range(1, 10) ne contient pas 10. C'est déroutant au début, et parfaitement régulier : le nombre de valeurs vaut exactement fin - debut, ce qui évite une addition mentale à chaque usage.
Pour aller jusqu'à 10 inclus, il faut écrire range(1, 11). Enveloppe un range dans list() quand on doute : on verra les valeurs.

L'accumulateur est le motif le plus employé de toute la programmation, et le plus difficile à voir pour qui débute : la variable total change à chaque tour, et rien sur la page ne le montre. La figure ci-dessous le déroule.

pas 1 / 8
1total = 0
2for n in [3, 7, 2]:
3 total = total + n
4print(total)

Variables

total0
Le programme, exécuté pas à pas. La ligne surlignée est celle qui vient de s'exécuter, et le tableau de droite donne l'état des variables juste après.

Trois choses se lisent sur cette trace, et aucune ne se déduit du code seul.

total = 0 s'exécute une seule fois, avant la boucle. Le placer à l'intérieur remettrait le compteur à zéro à chaque tour, et c'est l'erreur la plus fréquente sur ce motif.

La ligne for revient à chaque tour : c'est elle qui donne à n sa valeur suivante. La boucle n'est pas un bloc qu'on exécute trois fois d'affilée, c'est un aller-retour entre l'en-tête et le corps.

Enfin, n existe encore après la boucle et vaut 2, la dernière valeur prise. Python ne l'efface pas en sortant.

Répéter tant qu'une condition tient : while

Définition

La boucle while répète un bloc tant que sa condition est vraie. On l'emploie quand on ne sait pas d'avance combien de tours seront nécessaires.

main.py
Sortie
>_ Prêt à exécuter…
Lequel choisir : une seule question
Est-ce que je sais, avant de commencer, sur quoi je boucle ?
Oui, une liste, un nombre de tours, un fichier : c'est un for.
Non, cela dépend de ce qui se passera pendant : c'est un while. Attendre une saisie correcte, jouer jusqu'à ce qu'un joueur gagne, lire jusqu'à la fin d'un flux.
Les débutants écrivent souvent un while avec un compteur qu'ils incrémentent à la main, là où un for tenait en une ligne. Si on écrit compteur += 1 à la fin du while, demandons-nous si un for ne ferait pas l'affaire.

Un while a besoin de trois choses, et en oublier une est l'erreur classique : initialiser la variable avant, la tester dans la condition, et la faire évoluer dans le bloc.

Le bloc suivant est faux exprès : la troisième manque.

main.py
Sortie
>_ Prêt à exécuter…

Rien ne fait grandir compteur, la condition reste vraie pour toujours. Au bout de quelques secondes, la plateforme interrompt l'exécution et affiche un message de dépassement de temps. Sur la machine, il faudrait interrompre le programme à la main.

À faire. Ajoute compteur += 1 dans le bloc et relance.

Le while demande une vigilance que le for n'exige pas : c'est au programmeur de faire progresser la condition vers sa fin. Dérouler la trace montre exactement ce qui rapproche du terme.

pas 1 / 16
1n = 5
2resultat = 1
3while n > 1:
4 resultat = resultat * n
5 n = n - 1
6print(resultat)

Variables

n5
Le programme, exécuté pas à pas. La ligne surlignée est celle qui vient de s'exécuter, et le tableau de droite donne l'état des variables juste après.

La ligne while est réévaluée à chaque tour, y compris la dernière fois où elle est fausse et fait sortir. La ligne n = n - 1 est la seule qui rapproche de cette sortie : la retirer donnerait une boucle sans fin, et le programme ne s'arrêterait jamais de lui-même.

break et continue

InstructionEffet
breaksort de la boucle immédiatement
continuepasse au tour suivant sans finir celui-ci
main.py
Sortie
>_ Prêt à exécuter…

Boucles imbriquées

Une boucle peut en contenir une autre. La boucle intérieure se déroule entièrement à chaque tour de la boucle extérieure.

main.py
Sortie
>_ Prêt à exécuter…

Trois tours extérieurs, deux tours intérieurs à chaque fois : six lignes. C'est le schéma qui sert à parcourir un tableau à deux dimensions.

Vérification rapideon peut se reprendre

1.Que produit range(1, 5) ?

2.Avec note = 15, combien de lignes affiche une suite de trois if indépendants dont les conditions sont >= 10, >= 14 et >= 16 ?

3.if choix == 1 or 2: avec choix = 9. Que se passe-t-il ?

4.Quand faut-il un while plutôt qu'un for ?

5.Que vaut i juste après for i in range(3): pass ?

À mettre en pratique

FizzBuzz. Affiche les nombres de 1 à 20. Pour les multiples de 3, affiche Fizz ; pour les multiples de 5, Buzz ; pour les multiples de 3 et de 5, FizzBuzz.

main.py
Sortie
>_ Prêt à exécuter…
Afficher la solution
main.py
Sortie
>_ Prêt à exécuter…

L'ordre est ce qui compte. Le cas « multiple de 3 et de 5 » vient en premier : mis en dernier, il ne serait jamais atteint, puisqu'un multiple de 15 est déjà un multiple de 3 et sortirait sur le premier elif.

C'est exactement le piège de la section sur elif : avec une suite d'elif, le premier vrai gagne, donc le cas le plus restrictif se place en tête.

Synthèse

  • L'indentation définit les blocs. Ce qui est décalé appartient au if ou à la boucle.
  • if / elif / else sont testés dans l'ordre, et Python s'arrête au premier vrai.
  • Une suite de if évalue tout : ce n'est pas la même chose qu'un elif, et cela ne provoque aucune erreur.
  • = colle une étiquette, == compare. Dans un if, on compare.
  • if x == 1 or 2 est toujours vrai : répéter la variable, ou employer in.
  • for quand on sait sur quoi on boucle, while quand on ne sait pas combien de tours.
  • Dans range(a, b), la borne de fin est exclue.
  • Un while a besoin d'initialiser, tester, faire évoluer. Oublier le troisième donne une boucle infinie.

Mettre en pratique