Aller au contenu

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 :

Schéma de la séquence

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 !).

nom = input("Votre nom : ")
if nom == "Felix" :
    print("Felix... Joli nom...")
print("Enchanté !")

Et ses deux sorties possible

Votre nom : Felix
Felix... Joli nom...
Enchanté !
Votre nom : pas Felix
Enchanté !

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 :

if condition : 
    instruction

Visuellement, ça donne :

Schéma instruction conditionnelle

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.

if condition : 
    instruction1
    instruction2
    instruction3

Qu'on peut représenter :

Schéma if avec sequence

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 :

Schéma if imbriqués

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 :

Age ? 18
Vous êtes donc majeur(e) !
Enchanté
Age ? 17
Enchanté !
  • 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 !
age = int(input("Age ? "))
if age >= 18 :
    print("Vous êtes donc majeur() !")
print("Enchanté !")

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".

Age ? 18
Majeur
Age ? 17
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 <
age = int(input("Age ? "))
if age >= 18:
    print("Majeur")
if age < 18:
    print("Mineur")

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 :

Age ? 26
Majeur
Age ? 79
Majeur
Et vieux

  • Utilisez deux if successifs.
  • N'oubliez pas la conversion
age = int(input("Age ? "))
if age >= 18:
    print("Majeur")
if age >= 60:
    print("Et vieux")

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 :

Age ? 18
Vous avez 18 ans !

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 :

age = int(input("Age ? "))
if age >= 18:
    print("Majeur")
if age < 18:
    print("Mineur")
Ici, les conditions des deux if 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 :

if condition:
    instruction1
else:
    instruction2

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 :

Schéma d'un if...else

On peut donc réécrire notre programme d'une manière plus expressive :

age = int(input("Age ? "))
if age >= 18:
    print("Majeur")
else:
    print("Mineur")

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 :

Age ? 26
Vous ne seriez pas prof de NSI par hasard ?
Age ? 18
Majeur
Age ? 17
Mineur

  • 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é ==.
age = int(input("Age ? "))
if age == 26:
    print("Vous ne seriez pas prof de NSI par hasard ?")
else :
    if age >= 18:
        print("Majeur")
    else:
        print("Mineur")

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 :

op ? *
fois

op ? + 
plus

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 de else
  • 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 !

op = input("op ? ")
if op == "+":
    print("plus")
if op == "-":
    print("moins")
if op == "*":
    print("fois")

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

op ? /
operation inconnue

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 :

if op != "+" and op != "-" and op != "*":
    print("operation inconnue")

Ce qui donne le programme complet :

op = input("op ? ")    
if op == "+":
    print("plus")
if op == "-":
    print("moins")
if op == "*":
    print("fois")
if op != "+" and op != "-" and op != "*":
    print("operation inconnue")

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 :

if condition1:
    instruction1
else:
    if condition2: 
        instruction2

Et elle prends cette forme, utilisant le mot clé elif :

if condition1:
    instruction1
elif condition2:
    instruction2

Visuellement, ça donne :

Schéma de if elif

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'un else et de deux elif.
  • La condition finale sera le else.
  • En dehors du else, il y a très peu de changement à faire.
op = input("op ? ")    
if op == "+":
    print("plus")
elif op == "-":
    print("moins")
elif op == "*":
    print("fois")
else:
    print("operation inconnue")

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 :

n1 ? 10
op ? +
n2 ? 30
10 + 30 = 40
n1 ? 20
op ? /
n2 ? 30
10 / 30 = operation inconnue
  • 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.

n1 = int(input("n1 ? "))
op = input("op ? ")    
n2 = int(input("n2 ? "))

if op == "+":
    res = n1 + n2
elif op == "-":
    res = n1 - n2 
elif op == "*":
    res = n1 * n2
else:
    res = "operation inconnue"

print(str(n1) + op + str(n2) + " = " + str(res))

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 :

while condition:
    instruction

Elle a le comportement suivant :

  1. La condition est testée
  2. Si la condition est vérifiée, le corps (l'instruction) est executé, et on retourne en 1.
  3. Si la condition n'est pas vérifiée, on passe à l'instruction suivante.

Un petit visuel peut aider à se représenter l'instruction :

Schéma du while

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

0
1
2
3
4
5
6
7
8
9

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 :

nombre ? 10
Bravo !
nombre ? 111
nombre ? 1
nombre ? 0
nombre ? 5
nombre ? 23049
nombre ? 10
Bravo !
  • 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 !=.
nombre = int(input("nombre ? "))
while nombre != 10:
    nombre = int(input("nombre ?"))
print("Bravo !")
nombre = 0 ##valeur arbitraire qui vérifie != 10 pour rentrer dans la boucle
while nombre != 10:
    nombre=int(input("nombre ? "))
print("Bravo !")

Voilà un exemple d'utilisation de l'instruction pass utilisée dans un code complet. Toutefois, je déconseille de coder dans ce style. Il n'est pas accepté facilement par tout le monde, et peut dérouter ceux qui n'en n'ont pas l'habitude.

while int(input("nombre ? ")) != 10:
    pass
print("Bravo !")

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 :

Je compte jusqu'à ? 5
1
2
3
4
5
Je compte jusqu'à ? 21
La flemme !

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 :

Départ ? 4
4
3
2
1
0

  • 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
dep = int(input("Départ ? "))
while dep >= 0:
    print(dep)
    dep = dep - 1

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.

if condition:
    #instructions si condition vérifiée

Ajouter un else après un if permet d'executer des instructions seulement si la condition n'est pas vérifiée.

if condition:
    #instructions si condition vérifiée
else:
    #instructions si condition non 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 :

while condition:
    #instructions tant que la condition est vraie