Structures de contrôle en Python
Les exercices illustrant ce chapitre peuvent se retrouver sur la page correspondante
On aimerait écrire des programmes qui executent des instructions en fonction des données qu'on leur soumet.
Par exemple, un programme qui affiche bonjour Félix
si on lui entre Félix
, et t'es qui ?
sinon.
Les éléments du langage qui nous permettent de ce genre de choix dans le langage Python sont appelées structures de contrôle. Leur présence est si importante qu'elle constitue une spécialisation du paradigme impératif, le paradigme impératif structuré, auquel se conforment presque tous les langages impératifs "modernes" (moins de 50 ans).
Retour sur la séquence
En fait, on a déjà utilisé une structure de contrôle : la séquence, qui exécute les instructions les unes après les autres. On ne reviendra pas là dessus, mais elle va nous permettre d'introduire une représentation visuelle d'un programme, dont nous nous servirons pour mieux nous représenter les structures de contrôle dans ce cours.
On représentera un programme par un ensemble de blocs, avec une entrée, et une sortie. Les "actions" (écrire en console, additionner des nombres, ...) seront représentées par des carrés. Les choix par des losanges. Les structures de contrôle sont aussi des instructions, elle seront donc encadrées par un carré quand elles seront présentées.
Une séquence est par exemple représentée comme suit :
Je vous conseille, si parfois vous êtes bloqués, de faire de tels schémas pour représenter le programme que vous voulez faire. Ne pensez pas au code, mais à quelles actions et décisions le programme doit prendre.
Instruction conditionnelle si ... alors
La prise de décision la plus simple, est le choix si (en anglais if). Il corresponds à exécuter des instructions uniquement si une condition est remplie, puis de reprendre à la suite dans tous les cas.
Voici un exemple de programme Python qui demande son nom à l'utilisateur, et si l'utilisateur réponds Felix
, il affiche Felix... Joli nom...
. Dans tous les cas, il affiche ensuite Enchanté !
. (vous pouvez évidemment utiliser votre nom à vous, il est sans doute aussi très joli !).
Et ses deux sorties possible
On voit ici plusieurs choses. La ligne print("Felix... Joli nom...")
est indentée, c'est à dire décalée vers la droite. Celà permet de définir les instructions qui dépendent de la condition. On appelle ça un bloc de code, qui constitue le corps du if
.
On peut indenter avec des espaces (souvent ce qui est choisi en Python, avec 4 espace par niveau d'indentation) ou des tabulations, l'important, c'est de toujours être consistent, sinon l'interpréteur Python lèvera une erreur.
Une instruction conditionnelle if a la syntaxe suivante :
Visuellement, ça donne :
La condition est une valeur booléenne. On peut donc y mettre toutes les comparaisons, ou même des expressions booléennes, que nous détaillerons plus tard dans le cours.
Par exemple :
if 5.0 < 10:
print(a < 10)
if 19.0 >= 20 and "texte" :
print("a quoi sert cette condition au fait ?")
On rappelle que la séquence est une instruction. Il peut alors y avoir plusieurs instructions à la suite dans le corps d'un if
. Il faut seulement qu'elles aient la même indentation.
Qu'on peut représenter :
Et bien entendu, une instruction conditionnelle est une instruction (c'est marqué dans le nom), donc on peut mettre un if
dans un if
. On parle alors de if
imbriqués (nested en anglais). Il faut eviter d'avoir trop d'imbrication dans le code, parce que ça le rends plus dur à lire. Le mieux c'est 1 seul niveau, et maximum 2-3 si on ne peut pas faire autrement.
if condition1 :
#premier niveau d'indentation : 4 espaces
if condition2 :
#second niveau d'indentation : 8 espaces
instruction
Qu'on peut représenter :
Remarque :
if
est un mot clé du langage. C'est un mot réservé, et on ne peut pas appeler une variable if.
Exercices
Exercice : majeur ou pas
Proposez un programme (4 lignes) qui demande à l'utilisateur son âge, si l'utilisateur a 18 ans ou plus, le programme affiche "Vous êtes donc majeur !" puis "Enchanté !"
exemple de trace d'execution :
- Utilisez un
if
, avec un opérateur supérieur ou égal>=
.. - N'oubliez pas de convertir la chaîne donnée par l'utilisateur en entier !
Exercice : majeur ou mineur
Ecrivez un programme qui demande à l'utilisateur son âge. Si il est majeur (18 ans ou plus), le programme affiche "Majeur". Sinon le programme affiche "Mineur".
- Utilisez deux
if
l'un après l'autre. L'un s'occupe du cas de l'utilisateur majeur, l'autre du cas de l'élève mineur. - N'oubliez pas la conversion !
- Le
if
pour majeur utilise un supérieur ou égal>=
- le
if
pour mineur utilise un inférieur stricte<
Exercice : majeur et vieux
Ecrivez un programme (5 lignes) qui demande l'âge de l'utilisateur. Si l'utilisateur est majeur, il doit afficher "Majeur". Si l'utilisateur a 60 ans ou plus, il doit afficher "Et vieux".
Exemples de trace :
- Utilisez deux
if
successifs. - N'oubliez pas la conversion
Instruction pass
Parfois, on veut laisser le corps d'un if
ou d'une autre structure de contrôle vide, le temps d'implanter le code qui va autour.
age = input("Age ? ")
if int(age) > 18:
#ici, on aimerait laisser vide, parce qu'on ne sait pas encore exactement ce qu'on va faire
print("Vous avez "+ age + " ans !")
Si on lance ce programme, Python va nous renvoyer une erreur d'indentation :
Traceback (most recent call last):
File "/home/felix/erreur.py", line 4
print("Vous avez "+ age + " ans !")
^^^^^
IndentationError: expected an indented block after 'if' statement on line 2
En fait, Python n'accepte pas qu'on laisse un bloc (le corps d'une instruction) vide. C'est pour nous éviter de potentielles erreurs d'inattention, où l'on oublierai d'indenter.
C'est à dire, Python se demande si on avait pas plutôt envie d'écrire ça :
age = input("Age ? ")
if int(age) > 18:
#ici, on aimerait laisser vide, parce qu'on ne sait pas encore exactement ce qu'on va faire
print("Vous avez "+ age + " ans !")
mais qu'on se serait trompés.
Python nous donne donc un moyen explicite de signifier qu'un bloc doit être vide : l'instruction pass
. Elle se met juste à la place du bloc vide, et ne fait rien :
age = input("Age ? ")
if int(age) > 18:
pass #voilà, c'est juste ça.
print("Vous avez "+ age + " ans !")
Si on lance ce programme, il s'execute correctement :
Cette instruction est très utile pendant qu'on ecrit un programme, pour ne pas avoir à tout écrire d'un seul coup, mais quand même pouvoir lancer le programme. En revanche, dans un programme fini, à part dans de très rares cas, elle ne doit pas être présente.
Instruction conditionnelle sinon
Quand on programme, on veut souvent faire des choix de la forme si X alors je fais quelque chose, sinon je fais AUTRE chose. C'était le cas dans le programme qu'on a fait dans l'exercice 2 à la section précédente :
Ici, les conditions des deuxif
sont opposées : si age >= 18
est vraie, alors age < 18
est fausse, et vice versa.
Même si ce code marche, il n'exprime pas bien ce que nous voulons faire, notre intention. Structurellement, on a l'impression que les deux if
représentent des choix distincts, alors qu'ils sont deux facettes d'un même choix.
Le but d'un langage de programmation est de bien exprimer un programme, pour qu'il soit compréhensible par les humains et vérifiable par les machines. Un programme bien exprimé est en général plus facile à lire et à modifier.
Python nous donne donc des éléments de syntaxe supplémentaires pour exprimer des choix. Le premier est le if ... else
, il prends cette forme :
Si la condition est remplie, on execute l'instruction (ou la séquence donc) 1, et pas l'instruction 2. Si la condition n'est pas remplie, on execute l'instruction 2 et pas l'instruction 1.
Visuellement, ça donne :
On peut donc réécrire notre programme d'une manière plus expressive :
Il a exactement le même comportement, mais le choix apparaît maintenant clairement. Il est plus simple à lire et à écrire, en particulier, on a pas besoin de se demander quelle est la condition opposée de age >= 18
.
Exercices
Exercice : 26 ans
Ecrire un programme qui demande son âge à l'utilisateur. Si l'utilisateur a 26 ans, le programme affiche Vous ne seriez pas prof de NSI par hasard ?
. Sinon, si l'utilisateur est majeur (18 ans ou plus), il doit afficher "Majeur", et "Mineur" sinon.
Exemple de traces :
- Il ya a un if...else, puis un if...else dans le else
- N'oubliez pas les conversions
- Pour vérifier si l'âge est égal a 26, il faut utiliser l'opérateur d'égalité
==
.
Instruction conditionnelle sinon si
Il arrive qu'on ait des choix multiples, sur des conditions dépendantes les unes des autres. On va faire une petite calculatrice. (chouette, c'est notre premier programme vraiment utile !)
Le principe est le suivant : on demande à l'utilisateur un nombre, puis une opération, puis un autre nombre. Ensuite, en fonction de l'opération qu'il a choisie. On va supporter trois opérations : addition, soustraction, multiplication.
On va commencer par écrire la structure du programme qui permet de choisir une opération.
Partie 1 : choix d'une opération
Ecrivez un programme (7 lignes) qui demande à l'utilisateur de rentrer +
, -
ou *
, puis et qui affiche le mot qui correspond à l'opération.
- +
-> plus
- -
-> moins
- *
-> fois
Exemples de trace :
MEME SI VOUS REUSSISSEZ L'EXERCICE, LISEZ L'AIDE, elle contient une astuce qui pourra vous aider par la suite.
- Vous n'avez besoin que de trois
if
dans ce programme, pas deelse
- Il n'y a pas non plus besoin de faire de conversion
- Utilisez l'opérateur d'égalité
==
Il est parfois bien de commencer par écrire ce que doit faire le programme en commentaire avant de coder, puis de remplacer les commentaires par le code correspondant
#on demande l'operation a l'utilisateur
# si "+" on affiche "plus"
# si "-" on affiche "moins"
# si "*" on affiche "fois"
Vous pouvez aussi dessiner la structure des décisions de votre programme sur une feuille, ça peut aider !
Le programme que nous venons de faire marche, mais il pourraît être plus expressif. En particulier, on ne voit pas que les trois possibilités appartiennent à un même choix.
Partie 2 : opération inconnue
Ajoutez un if
à la fin du programme pour afficher "operation inconnue" si l'opération rentrée n'est pas +
, -
ni x
Votre if doit vérifier que :
- l'opérateur est différent de "+"
- et que l'opérateur est différent de "-"
- et que l'opérateur est différent de "*"
Vous pouvez faire ça avec l'opérateur booléen ET and
, et l'opérateur d'inégalité !=
.
On ajoute if
suivant :
Ce qui donne le programme complet :
On peut voir que cette dernière condition est particulièrement compliquée. Celà vient du manque d'expressivité de notre programme. Pour pallier ce problème, on peut utiliser l'élément syntaxique sinon si ... alors. C'est une manière plus propre de présenter cette structure :
Et elle prends cette forme, utilisant le mot clé elif
:
Visuellement, ça donne :
On peut ajouter autant de elif
qu'on veut à la suite. Ils seront sont examinées dans l'ordre, jusqu'à trouver une condition qui est vraie. Les instructions correspondantes sont alors executées, et les elif
suivant du groupe sont ignorés.
if condition1:
instruction1
elif condition2:
instruction2
elif condition3:
instruction3
elif condition4:
instruction4
...
On peut aussi ajouter un else
après le dernier elif
, qui sera exécuté si aucune des conditions n'était vraie.
if condition1:
instruction1
elif condition2:
instruction2
elif condition3:
instruction3
else:
instruction4
Partie 3 : une seule structure
Utilisez des if
, elif
et else
pour modifier le code de la partie précédente (Partie 2) et rassembler tous les choix dans une même structure.
Le fait de changer le code d'un programme sans en modifier le comportement pour en améliorer l'expressivité s'appelle le refactoring. C'est une pratique très courante en informatique.
- Vous aurez besoin d'un
if
, d'unelse
et de deuxelif
. - La condition finale sera le
else
. - En dehors du else, il y a très peu de changement à faire.
Les elif
sont très pratiques quand on veut traiter quelques cas particuliers (avec les if
et elif
) et un cas général (avec else
). Dans notre cas, +
, -
et *
sont des cas particulier, et toutes les autres possibilités forment le cas général.
Partie 4 : On calcule enfin !
Ajoutez dans le programme deux instructions pour demander des nombres à l'utilisateur, puis modifiez le corps de chaque if
et elif
pour afficher le résultat de l'opération demandée.
Exemples de traces :
- N'oubliez pas les conversions
- Faites une opération à la fois
- Vous n'avez pas besoin de modifier la structure du code, seulement de changer le contenu des print
Cette solution détaille les étapes des traitements. Ce n'est pas la plus concise, mais elle est parfaitement acceptable !
n1 = int(input("n1 ? "))
op = input("op ? ")
n2 = int(input("n2 ? "))
if op == "+":
operation = str(n1) + " + " + str(n2) ##formattage de l'opération pour l'afficher
res = n1 + n2 ##calcul du résultat
print(operation + " = " + str(res)) ##affichage
elif op == "-":
operation = str(n1) + " - " + str(n2)
res = n1 - n2
print(operation + " = " + str(res))
elif op == "*":
operation = str(n1) + " * " + str(n2)
res = n1 * n2
print(operation + " = " + str(res))
else:
operation = str(n1) + " - " + str(n2)
print(operation + " = operation inconnue")
Cette solution est plus concise, mais quand même dure à lire, à cause des prints qui sont un peu longs.
n1 = int(input("n1 ? "))
op = input("op ? ")
n2 = int(input("n2 ? "))
if op == "+":
print(str(n1) + " + " + str(n2) + " = " + str(n1 + n2))
elif op == "-":
print(str(n1) + " - " + str(n2) + " = " + str(n1 - n2))
elif op == "*":
print(str(n1) + " * " + str(n2) + " = " + str(n1 * n2))
else:
print(str(n1) + op + str(n2) + " = operation inconnue")
Cette solution n'est pas celle qui était attendue, je la mets toutefois ici, parce qu'elle est plus concise en tout en évitant les longs prints, et constitue une solution "idéale". Elle evite les répétitions, on appelle ça factoriser le code, nous en rediscuterons plus tard dans ce cours.
Itération conditionnelle tant que
En programmation, on a très fréquemment besoin de répéter une séquence d'instructions tant qu'une condition est vérifiée. Par exemple :
- Mettre à jour la fenêtre de jeu tant que le joueur n'a pas perdu
- Redemander une entrée (par exemple un nombre) tant qu'elle n'est pas valide
- Appliquer le même traitement sur un grand nombre de données
- Chercher un résultat en faisant des essais successifs.
Celà passe par l'instruction d'itération conditionnelle, qui en Python prends la forme d'une boucle tant que (en anglais while). Elle a cette forme :
Elle a le comportement suivant :
- La condition est testée
- Si la condition est vérifiée, le corps (l'instruction) est executé, et on retourne en 1.
- Si la condition n'est pas vérifiée, on passe à l'instruction suivante.
Un petit visuel peut aider à se représenter l'instruction :
Par exemple, le programme suivant :
i = 0 #i pour iteration. C'est courant dans les boucles, donc c'est autorisé.
while i < 10:
print(i)
i = i + 1
affiche
Exercice : exactement 10
Ecrivez un programme qui : demande un nombre à l'utilisateur. Si ce nombre est 10, il s'arrête en affichant Bravo !
. Sinon, il redemande le nombre à l'utilisateur tant que l'utilisateur ne rentre pas 10.
Exemple de trace :
- Vous n'avez besoin que du while comme structure de contrôle. Pas de
if
, pas de séquence. - il vous faut utiliser
input
à l'intérieur du while - n'oubliez pas les conversions
- tant que le nombre n'est pas 10 veut dire que vous devrez probablement utiliser
!=
.
Le while étant une instruction, on peu bien évidemment l'inclure dans le corps d'une autre instruction, comme un if
ou un autre while
.
limite = int(input("Je compte jusqu'à ? "))
if limite < 20:
i = 1
while i <= limite:
print(i)
i = i + 1
else :
"La flemme !"
donne :
Exercice : compter à l'envers
Ecrivez un programme qui demande un nombre à l'utilisateur, et qui compte ensuite à l'envers jusqu'à zéro (inclus) à partir de ce nombre.
Exemple de trace :
- Il vous faut une variable dont la valeur diminue de 1 à chaque tour de boucle
- Vous affichez cette valeur à chaque tour de boucle
- Vous continuez tant que la valeur n'est pas inférieure à zéro
Les essentiels
Au Programme
séquence : si on écrit des instructions les unes en dessous des autres, elles sont executées dans l'ordre descendant.
if
: on peut utiliser un if pour exécuter des instruction seulement si une condition est vérifiée. La condtion est représentée par une valeur booléenne. True
si condition vérifiée, False
sinon.
Ajouter un else
après un if
permet d'executer des instructions seulement si la condition n'est pas vérifiée.
Si on veut executer des instructions si la condition d'un if
n'est pas vérifiée, et si une autre condition est vérifiée, on peut utiliser un elif
.
if condition1:
#instructions si condition 1 vérifiée
elif condition2:
#instructions si condition 1 non vérifiée et condition 2 vérifiée.
On peut ajouter plusieurs elif
à la suite, et aussi un else
à la fin.
if condition1:
#instructions si condition 1 vérifiée
elif condition2:
#instructions si condition 1 non vérifiée et condition 2 vérifiée
elif condition3:
#instructions si conditions 1 et 2 non vérifiées et condition 3 vérifiée
else:
#instructions si conditions 1 à 3 non vérifiées
On peut répéter des instructions tant qu'une condition est vraie en utilisant un while
: