Retour au cours

backend / python

Structures de contrôle : if, elif, else

Leçon 21 exercice

Explication

Ce que vous allez apprendre

  • Écrire des chaînes if/elif/else lisibles pour orienter le comportement d'un programme
  • Reconnaître les valeurs "falsy" (0, "", [], None) sans avoir à les lister de mémoire
  • Comprendre pourquoi is None est préférable à == None pour 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).

ValeurTruthy / Falsy
0, 0.0Falsy
"" (chaîne vide)Falsy
[], {}, set()Falsy
NoneFalsy
"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.

python
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 None est 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 chaines if/elif sur des structures.

Exercices pratiques

1 disponible
1

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.

Résoudre l’exercice →