Une première étape pour aller vers plus d’interactivité est d’ajouter à notre programme des conditions. Les conditions vont nous permettre d’effectuer une action ou une autre suivant la valeur d’une expression. Par exemple « affiche "gagné" si l’utilisateur a entré le bon nombre ».
Test d'égalité
Nous avons vu différents opérateurs arithmétiques mais il est maintenant temps de nous intéresser à une nouvelle catégorie : les opérateurs de comparaison.
À commencer par l’opérateur d’égalité, noté ==
.
Cet opérateur appliqué à deux valeurs renvoie un état vrai (True
) ou faux (False
) indiquant si les valeurs sont égales ou non.
>>> 1 == 1
True
>>> 1 == 2
False
>>> 2 == 2
True
Le test d’égalité fonctionne pour tous les types de données et quelles que soient les expressions.
>>> 3 + 5 == 2 * 4
True
>>> word = 'abc'
>>> word == 'ab' + 'c'
True
>>> word == 'ab' + 'cd'
False
Attention cependant aux comparaisons avec des flottants.
Si vous vous souvenez, on avait vu que les nombres flottants pouvaient comporter des erreurs d’arrondis.
Il peut ainsi arriver qu’une égalité entre flottants que l’on pense vraie ne le soit en fait pas, en raison de ces arrondis.
>>> 0.1 + 0.2 == 0.3
False
>>> 0.1 + 0.2 == 0.30000000000000004
True
De manière générale, évitez donc les tests d’égalité entre nombres flottants, nous verrons dans un prochain chapitre ce que l’on peut faire à la place.
Il est aussi possible de comparer des valeurs de types différents, mais le résultat sera souvent faux car des valeurs de types différents sont généralement considérées comme différentes (exception faite pour les nombres entiers et flottants).
>>> word == 2
False
>>> '2' == 2
False
>>> 2.0 == 2
True
Ainsi l’objectif est maintenant d’exécuter une action uniquement si un test d’égalité (une condition) est vérifié, c’est là qu’interviennent les blocs conditionnels !
Bloc conditionnel
Une condition en Python correspond à un bloc if
, traduction anglaise du mot « si ».
Un bloc est un élément de syntaxe que nous n’avons pas encore vu jusqu’ici : il s’agit de plusieurs lignes de code réunies au sein d’une même entité logique.
Un bloc conditionnel est introduit à l’aide du mot-clé if
suivi d’une expression et d’un signe :
.
Le contenu du bloc est constitué des lignes qui suivent, qui doivent être indentées par rapport à l’ouverture du bloc, c’est-à-dire décalées vers la droite avec des espaces pour les démarquer.
On utilise conventionnellement 4 espaces.
Le contenu du bloc ne sera exécuté que si l’expression du if
est évaluée à « vrai » (True
).
if 2 == 2:
print('> Nous sommes dans le bloc conditionnel')
print('> Ici encore')
print('Nous sommes en dehors du bloc')
Ainsi le code précédent se lit :
- Si 2 est égal à 2, afficher « Nous sommes dans le bloc conditionnel » et « Ici encore ».
- Dans tous les cas afficher « Nous sommes en dehors du bloc ».
Et s’exécute comme suit.
Comme on le voit, un bloc prend fin dès la première ligne qui n’est pas indentée.
Pour cet exemple comme pour ceux qui suivront, je vous conseille d’utiliser un fichier Python plutôt que l’interpréteur interactif qui gère assez mal les problématiques d’indentation. J’y reviens juste après.
Lorsque la condition est fausse, le contenu du bloc if
n’est jamais exécuté et on passe directement à la suite du programme.
if 1 == 2:
print("Cette ligne n'est jamais exécutée")
print('Cette ligne est en dehors du bloc')
Qui donne à l’exécution :
Mais les exemples qui précèdent ont peu d’intérêt car les conditions sont fixées et ont donc toujours la même valeur.
Il pourrait être intéressant par exemple d’interagir avec l’utilisateur à l’aide d’un input
.
nbr = int(input('Devinez le nombre secret : '))
if nbr == 42:
print('Bravo, vous avez trouvez le nombre mystère !')
print('Relancez le programme pour une nouvelle partie')
On peut alors exécuter le programme plusieurs fois pour tester nos réponses, et avoir une exécution différente selon ce que l’on saisit.
Interpréteur interactif
L’interpréteur interactif peut parfois poser problème quand on utilise des blocs. Il demande en effet de laisser une ligne vide après chaque bloc (ce qui n’est pas nécessaire autrement), sans quoi vous obtiendrez une erreur de syntaxe.
>>> if 2 == 2:
... print('Gagné')
... print('Fin')
File "<stdin>", line 3
print('Fin')
^
SyntaxError: invalid syntax
On remarque cela aux caractères utilisés par le prompt : quand nous sommes en dehors de tout bloc, les caractères >>>
sont utilisés.
Mais une fois dans un bloc, ce prompt se transforme en ...
, signifiant que l’interpréteur attend d’autres lignes à ajouter au bloc.
Tout ce qui est tapé derrière un ...
est donc considéré par l’interpréteur interactif comme appartenant toujours au même bloc, ce qui provoque une erreur de syntaxe lorsque l’indentation est absente.
Une ligne vide permet de demander à l’interpréteur de sortir du bloc, qui serait alors exécuté immédiatement avant de passer à la suite.
>>> if 2 == 2:
... print('Gagné')
...
Gagné
>>> print('Fin')
Fin
Dans un fichier, la première syntaxe est parfaitement valide, puisque ce sont les tabulations uniquement qui délimitent les blocs.
if 2 == 2:
print('Gagné')
print('Fin')
De la même manière, il est impossible d’avoir une ligne vide au milieu d’un bloc conditionnel dans l’interpréteur interactif, même si cette syntaxe est valide en Python.
if 2 == 2:
print('Gagné')
print('Tu es trop fort')
Ces limitations peuvent être très gênantes et c’est pourquoi l’interpréteur interactif est déconseillé pour des codes complexes. Il reste toutefois très utile pour tester rapidement un petit bout de code.
Blocs sur une ligne
Il faut relever une exception au fait que le contenu d’un bloc conditionnel soit toujours indenté.
Si un bloc se compose d’une seule ligne, il est possible de faire suivre cette ligne directement après le :
du if
, sans retour à la ligne ni indentation.
if nbr == 42: print('Bravo, vous avez trouvez le nombre !')
Cette forme est à déconseiller car elle fait perdre en lisibilité, mais elle reste néanmoins utile pour des cas particuliers comme une vérification rapide avec python -c
.
% python -c "if 2 * 21 == 42: print('Bravo')"
Bravo
Et sinon ?
Nous avons vu quoi faire quand une condition était vraie, mais ce n’est pas le seul cas qui nous intéresse. Une condition est en effet soit vraie soit fausse, et un traitement particulier doit pouvoir être apporté à ce deuxième cas de figure.
Python fournit pour cela le bloc else
(« sinon ») qui se place directement après un bloc if
.
Aucune expression n’est nécessaire derrière le mot-clé else
(pas de condition à préciser), le signe :
reste néanmoins obligatoire pour introduire le bloc.
Le contenu du bloc else
sera exécuté si et seulement si la condition du if
est fausse.
secret = 42
nbr = int(input('Devinez le nombre secret : '))
if nbr == secret:
print('Bravo, vous avez trouvez le nombre !')
else:
print('Perdu, le nombre était', secret)
print('Relancez le programme pour une nouvelle partie')
Le programme précédent se lit comme suit :
Le joueur entre un nombre.
- Si le nombre est égal à 42, afficher « Bravo […] ».
- Sinon, afficher « Perdu […] ».
Dans tous les cas, afficher « Relancez le programme […] ».
Avec nos blocs conditionnels, nous avons chaque fois deux issues : soit la condition du if
est vraie et nous entrons dans son bloc, soit elle est fausse et c’est le bloc else
qui est exécuté.
Il est en fait possible d’avoir plus d’options que cela en combinant plusieurs conditions, c’est-à-dire en testant une seconde condition quand la première est fausse.
Plutôt que d’avoir un simple « si / sinon » nous pourrions avoir « si / sinon si / sinon ».
Ce « sinon si » prend la forme du mot-clé elif
(contraction de « else if » en anglais), qui s’utilise donc suivi d’une nouvelle expression conditionnelle.
secret = 42
nbr = int(input('Devinez le nombre secret : '))
if nbr == secret:
print('Bravo, vous avez trouvez le nombre !')
elif nbr == secret - 1:
print('Un peu plus...')
else:
print('Perdu, le nombre était', secret)
print('Relancez le programme pour une nouvelle partie')
Ainsi, dans le cas où nbr
vaut secret
nous afficherons « Bravo », s’il vaut secret - 1
nous obtiendrons « Un peu plus » et nous aurons « Perdu » dans tous les autres cas.
Une structure conditionnelle peut contenir autant de blocs elif
que nécessaire (contrairement au else
qui ne peut être présent qu’une fois), pour tester différentes conditions à la suite.
secret = 42
nbr = int(input('Devinez le nombre secret : '))
if nbr == secret:
print('Bravo, vous avez trouvez le nombre !')
elif nbr == secret - 1:
print('Un peu plus...')
elif nbr == secret + 1:
print('Un peu moins...')
else:
print('Perdu, le nombre était', secret)
print('Relancez le programme pour une nouvelle partie')
Il faut bien noter qu’un bloc elif
dépend du if
et des autres elif
qui le précèdent, son contenu ne sera donc exécuté que si toutes les conditions précédentes se sont révélées fausses.
if
étant le mot-clé qui introduit une structure conditionnelle, il doit être placé avant les elif
/ else
.
De même, else
terminant cette structure, il se place à la suite de tous les elif
.
elif
et else
restent bien sûr optionnels, un bloc conditionnel peut ne contenir qu’un simple if
.
On peut aussi imaginer un if
suivi de elif
mais sans else
.
secret = 'p4ssw0rd'
password = input('Entrez le mot de passe : ')
if password == '':
print('Veuillez saisir un mot de passe valide')
elif password == secret:
print('Authentification réussie')
Structures multiples
Enchaînement
Les exemples présents dans les sections qui précèdent montraient des structures conditionnelles seules : chacune est introduite par un if
, peut comporter plusieurs clauses elif
et peut être terminée par un else
.
Mais dans un programme il est généralement nécessaire de tester différentes conditions et donc d’avoir plusieurs structures conditionnelles, c’est-à-dire plusieurs if
.
Dans un fichier, on placera ainsi les blocs conditionnels les uns à la suite des autres, et Python comprendra qu’il s’agit d’une nouvelle structure chaque fois qu’il verra un if
.
user = input("Entrez le nom d'utilisateur: ")
password = input("Entrez le mot de passe: ")
if user == 'admin':
print("Le compte administrateur est désactivé")
if password == '1234':
print("Mot de passe trop faible")
elif password == '4321':
print("C'est pas mieux")
Dans le code précédent, les deux structures conditionnelles sont indépendantes l’une de l’autre.
Le deuxième if / elif
est exécuté quelle que soit l’issue du premier if
.
Il se lit de la manière suivante :
L’utilisateur entre un nom et un mot de passe.
Si le nom d’utilisateur est « admin », afficher « Le compte administrateur est désactivé. »
Si le mot de passe est « 1234 », afficher « Mot de passe trop faible ».
Sinon, si le mot de passe est « 4321 », afficher « C’est pas mieux ».
Et comme on le voit, le elif
se rapporte toujours au if
qui le précède directement, il en est de même pour else
.
Encore une fois, attention aux exemples de code qui pourraient ne pas fonctionner dans l’interpréteur interactif. Ce dernier demandera toujours de laisser une ligne vide entre deux blocs conditionnels distincts.
Imbrication
Une autre manière de combiner plusieurs blocs conditionnels consiste à les imbriquer / emboîter.
Il est effectivement courant au sein d’un bloc if
de vouloir tester une nouvelle condition pour effectuer un traitement particulier.
Pour rappel, Python délimite les blocs de code par leur indentation, c’est-à-dire les 4 espaces laissées en début de ligne. Quand il n’y a qu’un seul bloc, on ne constate qu’un niveau d’indentation.
Mais pour imbriquer une nouvelle condition sous une autre, il va nous falloir passer au niveau d’indentation suivant en ajoutant encore 4 espaces. Ainsi, Python compte le nombre d’espaces présentes en début de ligne pour déterminer dans quel bloc il se trouve.
Cela nous donne aussi une démarcation visuelle pour bien voir comment s’agencent nos blocs conditionnels.
quit = input('Voulez vous quitter le programme (oui/non) ? ')
if quit == 'oui':
confirm = input('Vous êtes sûr (oui/non) ? ')
if confirm == 'oui':
print('Fermeture en cours...')
else:
print('Décidez-vous !')
else:
print('Ok, on continue.')
Je vous invite à recopier le code qui précède dans un fichier et à l’exécuter en testant les 3 combinaisons possibles.
On constate bien que la condition sur confirm
n’est exécutée que lorsque quit
vaut « oui », et que les else
sont indentés au même niveau que les if
auxquels ils se rapportent.