backend / python
Structures de contrôle : if, elif, else
Explication
Ce que vous allez apprendre
- Écrire des chaînes
if/elif/elselisibles pour orienter le comportement d'un programme - Reconnaître les valeurs "falsy" (
0,"",[],None) sans avoir à les lister de mémoire - Comprendre pourquoi
is Noneest préférable à== Nonepour tester une valeur nulle - Utiliser l'opérateur ternaire et le chaînage de comparaisons pour des conditions plus concises
- Découvrir
match/case(Python 3.10+) pour remplacer une longue chaîne de conditions
Dans quel contexte ?
Un développeur relit une revue de code où un collègue a écrit if utilisateur == None: pour vérifier qu'un utilisateur n'a pas été trouvé en base. Le commentaire de relecture pointe immédiatement ce détail : sur ce projet, une classe métier surcharge __eq__ et cette comparaison pourrait un jour renvoyer un résultat inattendu. Comprendre la différence entre == et is évite ce genre d'aller-retour en review.
Faire des choix
Un programme qui ne fait jamais de choix n'est qu'une suite d'instructions figées. Les structures conditionnelles sont ce qui permet à un programme de réagir différemment selon la situation, exactement comme nous décidons de prendre un parapluie ou non selon la météo. if, elif et else forment une chaîne de questions posées dans l'ordre : dès qu'une réponse est vraie, Python exécute le bloc correspondant et ignore le reste de la chaîne.
Vrai, faux, et tout ce qui ressemble à faux
Ce qui surprend souvent, c'est que Python ne demande pas uniquement des booléens pour ses conditions. Une liste vide, une chaîne vide, le nombre zéro ou None sont tous considérés comme faux (falsy) dans un if. C'est extrêmement pratique : écrire if not liste: est plus idiomatique que if len(liste) == 0:. À l'inverse, presque tout le reste est vrai (truthy).
| Valeur | Truthy / Falsy |
|---|---|
0, 0.0 | Falsy |
"" (chaîne vide) | Falsy |
[], {}, set() | Falsy |
None | Falsy |
"0" (chaîne non vide) | Truthy |
[0] (liste non vide) | Truthy |
Le piège du comparateur d'égalité avec None
Un réflexe à corriger tôt : ne jamais comparer à None avec ==, mais avec is. None est un objet unique en mémoire, donc is None teste une identité fiable et rapide, alors que == pourrait théoriquement être redéfini par une classe personnalisée et donner un résultat trompeur.
Piège fréquent
if utilisateur == None: peut sembler fonctionner, mais si utilisateur est une instance d'une classe qui redéfinit __eq__ (courant avec des ORM comme SQLAlchemy), le résultat peut devenir imprévisible. if utilisateur is None: reste toujours fiable, quel que soit le type de l'objet.
Une évolution récente : match/case
Depuis Python 3.10, match/case permet de remplacer de longues chaînes de if/elif quand on teste la structure d'une donnée plutôt qu'une simple valeur (un tuple, un dictionnaire). Ce n'est pas un simple switch comme dans d'autres langages : c'est un véritable filtrage de motif (pattern matching), très utile pour analyser des messages ou des réponses d'API.
Cette leçon prolonge directement la précédente : maintenant que vous savez manipuler des valeurs, vous apprenez à orienter le déroulement du programme selon elles.
Commandes & code
Structures de contrôle : if / elif / else
Prendre des decisions en fonction de conditions.
age = 17
if age < 13:
categorie = "enfant"
elif age < 18:
categorie = "adolescent"
else:
categorie = "adulte"
print(categorie)
# Operateurs de comparaison et logiques
a, b = 5, 10
print(a < b, a == b, a != b, a >= b)
print(a < b and b < 20) # ET logique
print(a > b or b > 5) # OU logique
print(not (a == b)) # negation
# Falsy vs Truthy : ce que Python considere comme "faux"
valeurs_falsy = [0, 0.0, "", [], {}, set(), None, False]
for v in valeurs_falsy:
assert not v
# Idiome pythonique : eviter "== True" / "== None"
utilisateur = None
if utilisateur is None: # comparaison d'identite pour None
print("Aucun utilisateur")
liste = []
if not liste: # test de "vide" idiomatique
print("Liste vide")
# Operateur ternaire (expression conditionnelle)
statut = "majeur" if age >= 18 else "mineur"
# Chaining de comparaisons (specifique a Python)
note = 15
if 10 <= note <= 20:
print("Note valide")
# match / case (Python 3.10+) : pattern matching structurel
def decrire_commande(commande: tuple):
match commande:
case ("deplacer", x, y):
return f"Deplacement vers ({x}, {y})"
case ("attaquer", cible) if cible != "allie":
return f"Attaque sur {cible}"
case ("attaquer", _):
return "Attaque annulee : cible alliee"
case _:
return "Commande inconnue"
print(decrire_commande(("deplacer", 3, 4)))
print(decrire_commande(("attaquer", "dragon")))
# match sur des structures de donnees (dict, classes)
def analyser_reponse(reponse: dict):
match reponse:
case {"status": 200, "body": body}:
return f"OK : {body}"
case {"status": int(code)} if code >= 500:
return "Erreur serveur"
case {"status": _}:
return "Autre statut"
print(analyser_reponse({"status": 200, "body": "hello"}))Résumé
is Noneest preferable a== None(compare l'identite, pas la valeur).- Les listes/dicts/chaines vides sont "falsy" : pas besoin de
len(x) == 0. match/case(3.10+) remplace avantageusement de longues chainesif/elifsur des structures.
Exercices pratiques
Mission : traquer un bug de comparaison dans un ORM maison
Objectif : Identifier pourquoi une comparaison avec == None se comporte mal sur des objets métier, et migrer le code vers match/case.
Contexte
Une équipe a écrit une petite classe Commande qui redéfinit __eq__ pour comparer deux commandes par leur numéro. Un développeur a ensuite écrit if commande == None: pour vérifier qu'aucune commande n'a été trouvée en base, et ce test se comporte de façon incohérente selon les cas.
Tu dois comprendre la cause exacte du bug, le corriger, puis remplacer une chaîne de conditions par un match/case plus lisible sur la structure d'une réponse API.