Python & AI Tutorials Logo
Programmation Python

13. Faire des choix avec match et case (pattern matching structurel)

Lorsque votre programme doit prendre des décisions en fonction de plusieurs valeurs ou motifs possibles, vous avez déjà appris à utiliser des chaînes if-elif-else au Chapitre 8. Python 3.10 a introduit une alternative puissante appelée pattern matching structurel en utilisant les instructions match et case. Cette fonctionnalité offre une manière plus propre et plus expressive de gérer des scénarios de prise de décision complexes.

Le pattern matching va au-delà de simples comparaisons de valeurs. Il vous permet de faire correspondre la structure et la forme des données, d’extraire des valeurs à partir d’objets complexes et d’exprimer des choix multiples sous une forme plus lisible. Même si les chaînes if-elif-else fonctionnent parfaitement dans de nombreuses situations, les instructions match-case excellent lorsque vous traitez plusieurs cas distincts, en particulier lorsque vous travaillez avec des données structurées.

13.1) Présentation des instructions match et case (en s’appuyant sur if-elif du Chapitre 8)

13.1.1) La structure de base de match-case

Une instruction match examine une valeur (appelée le sujet) et la compare à un ou plusieurs motifs définis dans des clauses case. Lorsqu’un motif correspond, Python exécute le bloc de code associé à ce cas.

Voici la structure de base :

python
match subject:
    case pattern1:
        # Code à exécuter si pattern1 correspond
    case pattern2:
        # Code à exécuter si pattern2 correspond
    case pattern3:
        # Code à exécuter si pattern3 correspond

Commençons par un exemple simple qui illustre le concept fondamental :

python
# Gestionnaire simple de codes d’état HTTP
status_code = 404
 
match status_code:
    case 200:
        print("Success: Request completed")
    case 404:
        print("Error: Page not found")
    case 500:
        print("Error: Server error")

Output:

Error: Page not found

Dans cet exemple, l’instruction match examine status_code (le sujet). Python vérifie chaque motif case dans l’ordre. Lorsqu’il constate que status_code vaut 404, il exécute le bloc de code correspondant puis quitte l’instruction match. Les cas restants ne sont pas vérifiés.

13.1.2) En quoi match-case diffère de if-elif-else

Vous vous demandez peut-être : « Ne pourrais-je pas écrire cela avec if-elif-else ? » Oui, c’est possible :

python
status_code = 404
 
if status_code == 200:
    print("Success: Request completed")
elif status_code == 404:
    print("Error: Page not found")
elif status_code == 500:
    print("Error: Server error")

Output:

Error: Page not found

Les deux versions produisent le même résultat. Cependant, match-case offre plusieurs avantages :

  1. Intention plus claire : l’instruction match montre explicitement que vous comparez une valeur à plusieurs possibilités
  2. Moins de répétition : vous ne répétez pas le nom de la variable dans chaque comparaison
  3. Motifs plus puissants : comme nous allons le voir, match-case peut faire bien plus que de simples tests d’égalité
  4. Meilleure lisibilité : pour des arbres de décision complexes, match-case est souvent plus facile à comprendre

13.1.3) Quand aucun motif ne correspond

Que se passe-t-il si aucun motif ne correspond ? L’instruction match se termine simplement sans exécuter aucun bloc case :

python
# Vérificateur de rôle utilisateur
user_role = "guest"
 
match user_role:
    case "admin":
        print("Full system access granted")
    case "moderator":
        print("Content management access granted")
    case "editor":
        print("Editing access granted")
 
print("Role check complete")

Output:

Role check complete

Puisque "guest" ne correspond à aucun motif, aucun bloc case ne s’exécute. Le programme continue avec le code après l’instruction match. Ce comportement est important à comprendre — contrairement aux chaînes if-elif-else où vous pouvez ajouter une clause else finale pour intercepter tous les autres cas, une instruction match de base sans motif attrape-tout ne fera rien silencieusement si aucun motif ne correspond.

13.1.4) Exemple pratique : système de sélection de menu

Construisons un exemple plus complet qui montre la clarté de match-case pour gérer les choix de l’utilisateur :

python
# Système de commande au restaurant
menu_choice = 3
 
match menu_choice:
    case 1:
        item = "Caesar Salad"
        price = 8.99
        print(f"You ordered: {item} - ${price}")
    case 2:
        item = "Grilled Chicken"
        price = 14.99
        print(f"You ordered: {item} - ${price}")
    case 3:
        item = "Vegetable Pasta"
        price = 12.99
        print(f"You ordered: {item} - ${price}")
    case 4:
        item = "Chocolate Cake"
        price = 6.99
        print(f"You ordered: {item} - ${price}")
 
print("Order submitted to kitchen")

Output:

You ordered: Vegetable Pasta - $12.99
Order submitted to kitchen

Cet exemple montre comment chaque cas peut contenir plusieurs instructions. Lorsque menu_choice correspond à 3, Python exécute les trois lignes dans ce bloc case : l’affectation de item, l’affectation de price et l’affichage de la confirmation de commande.

13.2) Utiliser le joker _, les motifs littéraux et des motifs multiples

13.2.1) Le motif joker : intercepter tout le reste

Le caractère de soulignement _ est un motif spécial qui correspond à n’importe quoi. Il est généralement utilisé comme dernier cas pour gérer toutes les valeurs qui n’ont pas correspondu aux motifs précédents — similaire à une clause else finale dans une chaîne if-elif-else :

python
# Gestionnaire de codes d’état HTTP avec cas par défaut
status_code = 403
 
match status_code:
    case 200:
        print("Success: Request completed")
    case 404:
        print("Error: Page not found")
    case 500:
        print("Error: Server error")
    case _:
        print(f"Unhandled status code: {status_code}")

Output:

Unhandled status code: 403

Le motif _ agit comme un attrape-tout. Puisque 403 ne correspond à aucun des cas spécifiques, le motif joker correspond et exécute son bloc. Le motif joker correspondra à n’importe quelle valeur, donc il doit toujours être placé en dernier — tout cas placé après lui ne serait jamais exécuté.

Voici pourquoi le joker est utile en pratique :

python
# Planificateur par jour de la semaine
day = "Saturday"
 
match day:
    case "Monday":
        print("Team meeting at 9 AM")
    case "Wednesday":
        print("Project review at 2 PM")
    case "Friday":
        print("Weekly report due")
    case _:
        print(f"{day}: No scheduled events")

Output:

Saturday: No scheduled events

Sans le motif joker, si day valait "Saturday", "Sunday" ou toute autre valeur, l’instruction match se terminerait silencieusement sans sortie. Le joker garantit que vous gérez les cas inattendus ou non spécifiés de façon élégante.

13.2.2) Motifs littéraux : faire correspondre des valeurs spécifiques

Les motifs littéraux (literal patterns) correspondent à des valeurs exactes. Nous les utilisons déjà — les nombres, les chaînes et les valeurs booléennes sont tous des motifs littéraux :

python
# Contrôleur de feux de circulation
light_color = "yellow"
 
match light_color:
    case "green":
        print("Go")
    case "yellow":
        print("Caution: Light changing soon")
    case "red":
        print("Stop")
    case _:
        print("Invalid light color")

Output:

Caution: Light changing soon

Vous pouvez utiliser des motifs littéraux de différents types, et match vérifie la valeur en tenant compte de son type, selon les mêmes règles que l’opérateur == :

python
# Validateur de configuration (en utilisant différents types littéraux)
setting_value = True
 
match setting_value:
    case True:        # littéral booléen
        print("Feature enabled")
    case False:       # littéral booléen
        print("Feature disabled")
    case None:        # littéral None
        print("Feature not configured")
    case 0:           # littéral entier
        print("Feature explicitly turned off")
    case "auto":      # littéral chaîne
        print("Feature set to automatic mode")
    case _:
        print("Invalid configuration value")

Output:

Feature enabled

Les motifs littéraux fonctionnent avec les entiers, les flottants, les chaînes, les booléens et None. Python vérifie l’égalité en utilisant les mêmes règles que l’opérateur ==.

13.2.3) Motifs multiples avec l’opérateur OR

Parfois, vous voulez exécuter le même code pour plusieurs valeurs différentes. Vous pouvez combiner plusieurs motifs en utilisant l’opérateur | (pipe), qui signifie « ou » :

python
# Détecteur de week-end
day = "Saturday"
 
match day:
    case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
        print("It's a weekday - time to work!")
    case "Saturday" | "Sunday":
        print("It's the weekend - time to relax!")
    case _:
        print("Invalid day name")

Output:

It's the weekend - time to relax!

L’opérateur | vous permet de spécifier plusieurs motifs qui doivent déclencher la même action. Si le sujet correspond à l’un des motifs séparés par |, ce cas s’exécute. C’est bien plus propre que d’écrire des cas séparés avec des blocs de code identiques.

Vous pouvez mélanger différents types de motifs avec | :

python
# Validateur d’entrée pour les questions oui/non
response = "yes"
 
match response:
    case True | "yes":
        print("You confirmed the action")
    case False | "no":
        print("You cancelled the action")
    case _:
        print("Please answer yes or no")

Output:

You confirmed the action

13.2.4) Capturer quelle alternative a correspondu avec as

Lorsque vous utilisez plusieurs motifs avec |, vous pouvez vouloir savoir quelle valeur spécifique a correspondu. Vous pouvez utiliser le mot-clé as pour capturer la valeur correspondante :

python
# Gestionnaire de codes d’état avec réponses groupées
status = 201
 
match status:
    case 200 | 201 | 202 | 204 as success_code:
        print(f"Success: {success_code}")
    case 400 | 401 | 403 | 404 as client_error:
        print(f"Client error: {client_error}")
    case 500 | 502 | 503 as server_error:
        print(f"Server error: {server_error}")
    case _:
        print("Unknown status code")

Output:

Success: 201

Le mot-clé as crée une variable de liaison qui capture l’alternative qui a correspondu. Dans cet exemple, success_code est lié à 201 parce que c’est la valeur précise qui a correspondu parmi les alternatives 200 | 201 | 202 | 204.

Voici un autre exemple montrant en quoi cela est utile pour la journalisation :

python
# Processeur de niveaux de log
log_level = "WARN"
 
match log_level:
    case "DEBUG" | "TRACE" as level:
        print(f"Verbose logging: {level}")
        print("Detailed diagnostic information will be recorded")
    case "INFO" | "NOTICE" as level:
        print(f"Informational: {level}")
        print("Normal operation messages will be recorded")
    case "WARN" | "WARNING" as level:
        print(f"Warning level: {level}")
        print("Potential issues detected")
    case "ERROR" | "FATAL" | "CRITICAL" as level:
        print(f"Error level: {level}")
        print("Immediate attention required")
    case _:
        print("Unknown log level")

Output:

Warning level: WARN
Potential issues detected

13.3) Extraire des valeurs avec des variables de liaison

13.3.1) Que sont les variables de liaison ?

Jusqu’ici, nous avons fait correspondre des valeurs littérales. Mais le pattern matching devient vraiment puissant lorsque vous pouvez capturer ou extraire des parties des données que vous faites correspondre. Une variable de liaison (binding variable) (également appelée motif de capture (capture pattern)) est un nom dans un motif qui capture la valeur correspondante et la rend disponible dans le bloc case.

Voici un exemple simple :

python
# Capture simple d’une valeur
command = "save"
 
match command:
    case "quit":
        print("Exiting program")
    case action:  # Ceci est une variable de liaison
        print(f"Executing action: {action}")

Output:

Executing action: save

Le motif action est une variable de liaison. Il correspond à n’importe quelle valeur (comme le joker _), mais contrairement à _, il capture cette valeur et l’assigne au nom action. Dans le bloc case, vous pouvez utiliser action pour faire référence à la valeur correspondante.

Distinction importante : une variable de liaison correspond à n’importe quoi, tout comme _. La différence est que _ ignore la valeur, tandis qu’une variable de liaison la capture pour l’utiliser dans le bloc case.

13.3.2) Variables de liaison vs jokers

Comparons directement les variables de liaison et les jokers :

python
# Utilisation du joker - la valeur n’est pas capturée
status = 403
 
match status:
    case 200:
        print("Success")
    case _:
        print("Some other status code")  # Impossible d’accéder à la valeur réelle

Output:

Some other status code

Maintenant avec une variable de liaison :

python
# Utilisation d’une variable de liaison - la valeur est capturée
status = 403
 
match status:
    case 200:
        print("Success")
    case code:  # La variable de liaison capture la valeur
        print(f"Status code {code} received")

Output:

Status code 403 received

La variable de liaison code capture la valeur 403, la rendant disponible dans le bloc case. Cela est utile lorsque vous devez travailler avec la valeur réelle qui n’a pas correspondu à vos motifs spécifiques.

13.3.3) Faire correspondre des motifs de tuples et extraire des composants

Le pattern matching devient particulièrement puissant avec des données structurées comme les tuples. Vous pouvez faire correspondre la forme d’un tuple et extraire ses composants simultanément. Bien que nous étudions les tuples en détail au Chapitre 15, cet exemple se concentre uniquement sur la façon dont les motifs de tuples fonctionnent dans les instructions match.

python
# Système de coordonnées - correspondance d’un motif de tuple
point = (3, 7)
 
match point:
    case (0, 0):
        print("Origin point")
    case (0, y):  # Correspond à n’importe quel point sur l’axe des y
        print(f"On y-axis at y={y}")
    case (x, 0):  # Correspond à n’importe quel point sur l’axe des x
        print(f"On x-axis at x={x}")
    case (x, y):  # Correspond à n’importe quel autre point
        print(f"Point at coordinates ({x}, {y})")

Output:

Point at coordinates (3, 7)

Décomposons ce qui se passe :

  1. Le sujet point est le tuple (3, 7)
  2. Python vérifie chaque motif case dans l’ordre
  3. Les trois premiers motifs ne correspondent pas parce qu’ils exigent la valeur 0 à une position spécifique, et le tuple (3, 7) n’a aucun élément égal à 0
  4. Le motif (x, y) correspond parce que c’est un tuple de deux éléments
  5. Python lie x à 3 et y à 7
  6. Le bloc case s’exécute avec ces valeurs capturées

Voici un autre exemple montrant différents motifs de tuples :

python
# Analyseur de couleur RGB
color = (255, 0, 0)
 
match color:
    case (0, 0, 0):
        print("Black")
    case (255, 255, 255):
        print("White")
    case (r, 0, 0):  # Rouge pur avec une intensité variable
        print(f"Pure red with intensity {r}")
    case (0, g, 0):  # Vert pur
        print(f"Pure green with intensity {g}")
    case (0, 0, b):  # Bleu pur
        print(f"Pure blue with intensity {b}")
    case (r, g, b):  # Toute autre couleur
        print(f"RGB color: red={r}, green={g}, blue={b}")

Output:

Pure red with intensity 255

Cette entrée correspond au motif (r, 0, 0) parce que le tuple a trois éléments, les deux derniers sont 0, et la première valeur est liée à r.

13.3.4) Faire correspondre des motifs de listes

Vous pouvez aussi faire correspondre des motifs de listes et en extraire des éléments. Nous couvrirons les listes en détail au Chapitre 14 ; pour l’instant, cet exemple se concentre sur la façon dont les motifs de listes fonctionnent dans les instructions match :

python
# Commande avec arguments
command = ["move", "north", "5"]
 
match command:
    case ["quit"]:
        print("Exiting game")
    case ["look"]:
        print("You look around the room")
    case ["move", direction]:
        print(f"Moving {direction}")
    case ["move", direction, distance]:
        print(f"Moving {direction} for {distance} steps")
    case _:
        print("Unknown command")

Output:

Moving north for 5 steps

Le motif ["move", direction, distance] correspond à une liste de trois éléments dont le premier élément est "move". Il capture le deuxième élément sous direction et le troisième sous distance.

Voici un exemple pratique avec des longueurs de listes variables :

python
# Processeur d’articles d’un panier d’achat
item = ["laptop", 999.99, 2]
 
match item:
    case [name]:  # Article avec seulement un nom
        print(f"Item: {name} (no price or quantity specified)")
    case [name, price]:  # Article avec nom et prix
        print(f"Item: {name}, Price: ${price}, Quantity: 1 (default)")
    case [name, price, quantity]:  # Informations complètes sur l’article
        total = price * quantity
        print(f"Item: {name}, Price: ${price}, Quantity: {quantity}")
        print(f"Subtotal: ${total}")
    case _:
        print("Invalid item format")

Output:

Item: laptop, Price: $999.99, Quantity: 2
Subtotal: $1999.98

Le cas [name, price, quantity] s’exécute parce que la liste a exactement trois éléments, et chaque élément est lié à la variable correspondante.

13.3.5) Faire correspondre des motifs de dictionnaires

Le pattern matching fonctionne aussi avec les dictionnaires, en vous permettant de faire correspondre des clés spécifiques et d’en extraire les valeurs. Bien que nous étudions les dictionnaires en détail au Chapitre 16, cette section se concentre uniquement sur la façon dont les motifs de dictionnaires fonctionnent dans les instructions match.

python
# Processeur de profil utilisateur
user = {"name": "Alice", "role": "admin", "active": True}
 
match user:
    case {"role": "admin", "active": True}:
        print("Active administrator - full access granted")
    case {"role": "admin", "active": False}:
        print("Inactive administrator - access suspended")
    case {"role": role, "active": True}:  # Capturer la valeur de role
        print(f"Active user with role: {role}")
    case {"role": role, "active": False}:
        print(f"Inactive user with role: {role}")
    case _:
        print("Invalid user profile")

Output:

Active administrator - full access granted

Le cas {"role": "admin", "active": True} s’exécute parce que les motifs de dictionnaires exigent la correspondance de paires clé–valeur, et cette correspondance exacte est vérifiée avant des motifs plus généraux.

Les motifs de dictionnaires sont flexibles : ils correspondent si les clés spécifiées existent avec les valeurs spécifiées, même si le dictionnaire a des clés supplémentaires :

python
# Gestionnaire de réponse API
response = {"status": "success", "data": {"id": 123, "name": "Product"}, "timestamp": "2025-12-17"}
 
match response:
    case {"status": "error", "message": msg}:
        print(f"Error occurred: {msg}")
    case {"status": "success", "data": data}:
        print(f"Success! Data received: {data}")
    case _:
        print("Unknown response format")

Output:

Success! Data received: {'id': 123, 'name': 'Product'}

Le motif {"status": "success", "data": data} correspond même si le dictionnaire contient une clé "timestamp" supplémentaire. Le motif exige seulement que les clés spécifiées existent avec les valeurs spécifiées (ou des motifs).

13.3.6) Combiner des littéraux et des variables de liaison

Vous pouvez mélanger des motifs littéraux et des variables de liaison pour créer une logique de correspondance sophistiquée : Contrairement aux exemples de tuples précédents qui se concentraient sur la correspondance de structure et de position, cet exemple montre comment des valeurs littérales et des variables de liaison peuvent être combinées pour implémenter une logique de décision du monde réel.

python
# Routeur de requêtes HTTP
request = ("GET", "/api/users", 42)
 
match request:
    case ("GET", "/", None):
        print("Homepage request")
    case ("GET", path, None):
        print(f"GET request for: {path}")
    case ("POST", path, data):
        print(f"POST request to {path} with data: {data}")
    case ("GET", path, user_id):
        print(f"GET request for {path} with user ID: {user_id}")
    case _:
        print("Unsupported request type")

Output:

GET request for /api/users with user ID: 42

Cet exemple montre comment vous pouvez faire correspondre des valeurs spécifiques (comme "GET") tout en en capturant d’autres (comme path et user_id) dans le même motif.

13.3.7) Exemple pratique : gestionnaire d’événements

Construisons un exemple complet qui démontre la puissance des variables de liaison :

python
# Gestionnaire d’événements de jeu
event = ("player_move", {"x": 10, "y": 5, "speed": 2})
 
match event:
    case ("player_move", {"x": x, "y": y}):
        print(f"Player moved to position ({x}, {y})")
    case ("player_attack", {"target": target, "damage": damage}):
        print(f"Player attacked {target} for {damage} damage")
    case ("item_pickup", {"item": item_name}):
        print(f"Player picked up: {item_name}")
    case ("game_over", {"score": final_score}):
        print(f"Game ended. Final score: {final_score}")
    case (event_type, data):
        print(f"Unknown event type: {event_type}")
        print(f"Event data: {data}")

Output:

Player moved to position (10, 5)

Ce gestionnaire d’événements fait correspondre des tuples contenant un type d’événement et un dictionnaire de données d’événement. Il extrait des valeurs spécifiques du dictionnaire selon le type d’événement, ce qui facilite le traitement de différents types d’événements avec un code propre et lisible.

13.4) Ajouter des conditions supplémentaires avec la garde if

13.4.1) Que sont les gardes ?

Parfois, vous devez faire correspondre un motif et vérifier une condition supplémentaire. Une garde if (if guard) est une condition supplémentaire que vous pouvez ajouter à un motif de case avec le mot-clé if. Le cas ne correspond que si le motif correspond et si la condition de garde est vraie.

Voici la syntaxe :

python
match subject:
    case pattern if condition:
        # Le code s’exécute uniquement si pattern correspond ET que condition est vraie

Voyons un exemple simple :

python
# Contrôle d’accès basé sur l’âge
age = 16
 
match age:
    case age if age >= 18:
        print("Adult - full access granted")
    case age if age >= 13:
        print("Teen - limited access granted")
    case age if age >= 0:
        print("Child - parental supervision required")
    case _:
        print("Invalid age")

Output:

Teen - limited access granted

Dans cet exemple, la variable de liaison age capture la valeur, et la garde if age >= 13 ajoute une condition supplémentaire. Le cas ne correspond que si la valeur est 13 ou plus. Puisque age vaut 16, le deuxième cas correspond et s’exécute.

13.4.2) Comment les gardes sont évaluées

Comprendre l’ordre d’évaluation est important. Voici une visualisation détaillée montrant comment les gardes interagissent avec le pattern matching :

Non

Oui

Oui

Non

Oui

Non

Vérifier le motif du case

Le motif correspond ?

Essayer le case suivant

Évaluer la condition de garde

La garde est True ?

Exécuter le bloc case

Quitter l’instruction match

D’autres cases ?

Aucune correspondance - continuer après match

Python vérifie d’abord si le motif correspond. Ce n’est que si le motif correspond que Python évalue la condition de garde. Si la garde est fausse, Python passe au cas suivant — même si le motif correspondait.

Voici un exemple qui le démontre :

python
# Système d’avertissement de température
temperature = 25
 
match temperature:
    case temp if temp > 35:
        print(f"Extreme heat warning: {temp}°C")
    case temp if temp > 30:
        print(f"High temperature alert: {temp}°C")
    case temp if temp > 20:
        print(f"Comfortable temperature: {temp}°C")
    case temp if temp > 10:
        print(f"Cool temperature: {temp}°C")
    case temp:
        print(f"Cold temperature: {temp}°C")

Output:

Comfortable temperature: 25°C

Chaque cas utilise la variable de liaison temp pour capturer la valeur de la température, puis applique une garde pour vérifier si elle se situe dans une plage spécifique. Les cas sont vérifiés dans l’ordre, donc le premier cas correspondant dont la garde est vraie s’exécute.

13.4.3) Gardes avec des motifs littéraux

Vous pouvez combiner des gardes avec des motifs littéraux pour créer une correspondance plus spécifique :

python
# Calculateur de remise basé sur le type d’article et la quantité
item = ("book", 5)
 
match item:
    case ("book", quantity) if quantity >= 10:
        discount = 0.20  # 20% de remise pour 10+ livres
        print(f"Bulk book order: {quantity} books, {discount*100}% discount")
    case ("book", quantity) if quantity >= 5:
        discount = 0.10  # 10% de remise pour 5-9 livres
        print(f"Book order: {quantity} books, {discount*100}% discount")
    case ("book", quantity):
        discount = 0.0  # Aucune remise pour moins de 5 livres
        print(f"Book order: {quantity} books, no discount")
    case (item_type, quantity):
        print(f"Order: {quantity} {item_type}(s)")

Output:

Book order: 5 books, 10.0% discount

Le motif ("book", quantity) correspond à un tuple dont le premier élément est "book". La garde if quantity >= 5 ajoute la condition que la quantité doit être au moins de 5.

13.4.4) Gardes avec des conditions complexes

Les gardes peuvent utiliser n’importe quelle expression booléenne, y compris des conditions complexes avec and, or et not :

python
# Évaluateur de notes d’un étudiant avec prise en compte de l’assiduité
student = {"name": "Bob", "grade": 85, "attendance": 75}
 
match student:
    case {"grade": g, "attendance": a} if g >= 90 and a >= 90:
        status = "Excellent"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 80 and a >= 80:
        status = "Good"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 70 and a >= 70:
        status = "Satisfactory"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 60 or a >= 60:
        status = "Needs Improvement"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case _:
        print("Failing - immediate intervention required")

Output:

Grade: 85, Attendance: 75% - Status: Satisfactory

La garde if g >= 70 and a >= 70 exige que la note et l’assiduité soient toutes deux au moins à 70. Puisque Bob a une note de 85 et une assiduité de 75%, ce cas correspond.

13.4.5) Exemple pratique : système d’authentification utilisateur

Construisons un exemple complet qui utilise des gardes pour implémenter un système d’authentification réaliste :

python
# Authentification utilisateur avec accès basé sur les rôles
user = {"username": "alice", "role": "admin", "active": True, "login_attempts": 0}
 
match user:
    case {"active": False}:
        print("Account suspended - contact administrator")
    case {"login_attempts": attempts} if attempts >= 3:
        print("Account locked due to too many failed login attempts")
    case {"role": "admin", "active": True}:
        print("Admin access granted - full system privileges")
    case {"role": "moderator", "active": True}:
        print("Moderator access granted - content management privileges")
    case {"role": role, "active": True} if role in ["editor", "author"]:
        print(f"{role.capitalize()} access granted - content creation privileges")
    case {"role": "user", "active": True}:
        print("User access granted - basic privileges")
    case _:
        print("Access denied - invalid user profile")

Output:

Admin access granted - full system privileges

Cet exemple démontre comment les gardes peuvent implémenter une logique métier complexe. Le système vérifie plusieurs conditions : état du compte, tentatives de connexion et autorisations basées sur les rôles. Chaque cas gère un scénario spécifique, rendant la logique d’authentification claire et facile à maintenir.

13.5) Faire correspondre des formes simples de séquences et de mappings

13.5.1) Faire correspondre des séquences de longueur variable

Parfois, vous devez faire correspondre des séquences de longueurs variables. Le pattern matching de Python prend cela en charge avec l’opérateur *, qui capture zéro ou plusieurs éléments.

python
# Analyseur de commandes avec arguments variables
command = ["copy", "file1.txt", "file2.txt", "file3.txt", "backup/"]
 
match command:
    case ["help"]:
        print("Available commands: copy, move, delete")
    case ["copy", source, destination]:
        print(f"Copying {source} to {destination}")
    case ["copy", *sources, destination]:
        print(f"Copying {len(sources)} files to {destination}")
        print(f"Source files: {sources}")
    case ["delete", *files]:
        print(f"Deleting {len(files)} file(s): {files}")
    case _:
        print("Unknown command")

Output:

Copying 3 files to backup/
Source files: ['file1.txt', 'file2.txt', 'file3.txt']

Le motif ["copy", *sources, destination] correspond à une liste qui commence par "copy", se termine par une destination et possède n’importe quel nombre de fichiers source au milieu. Le *sources capture tous les éléments du milieu sous forme de liste.

Important : vous ne pouvez utiliser qu’un seul motif * par motif de séquence, et il capture des éléments sous forme de liste :

python
# Analyseur d’entrées de logs
log_entry = ["2025-12-17", "10:30:45", "ERROR", "Database", "connection", "timeout"]
 
match log_entry:
    case [date, time, "ERROR", *error_details]:
        print(f"Error on {date} at {time}")
        print(f"Error details: {' '.join(error_details)}")
    case [date, time, "WARNING", *warning_details]:
        print(f"Warning on {date} at {time}")
        print(f"Warning details: {' '.join(warning_details)}")
    case [date, time, level, *message]:
        print(f"{level} on {date} at {time}: {' '.join(message)}")

Output:

Error on 2025-12-17 at 10:30:45
Error details: Database connection timeout

13.5.2) Combiner des motifs de séquence avec des gardes

Vous pouvez utiliser des gardes avec des motifs de séquence pour ajouter des conditions supplémentaires :

python
# Analyseur de liste de notes
grades = [85, 92, 78, 95, 88]
 
match grades:
    case []:
        print("No grades recorded")
    case [grade] if grade >= 90:
        print(f"Single excellent grade: {grade}")
    case [grade] if grade < 60:
        print(f"Single failing grade: {grade}")
    case [*all_grades] if len(all_grades) >= 5 and sum(all_grades) / len(all_grades) >= 90:
        average = sum(all_grades) / len(all_grades)
        print(f"Excellent performance! Average: {average:.1f}")
    case [*all_grades] if len(all_grades) >= 5:
        average = sum(all_grades) / len(all_grades)
        print(f"Performance review: {len(all_grades)} grades, Average: {average:.1f}")
    case [*all_grades]:
        print(f"Insufficient data: only {len(all_grades)} grade(s)")

Output:

Performance review: 5 grades, Average: 87.6

Le motif [*all_grades] capture tous les éléments de la liste, et la garde vérifie à la fois la longueur et calcule la moyenne pour déterminer le message approprié.


Le pattern matching avec match et case fournit une manière puissante et expressive de gérer des prises de décision complexes en Python. De la simple correspondance de valeurs aux motifs structurels sophistiqués avec des gardes, cette fonctionnalité vous permet d’écrire un code plus propre et plus facile à maintenir pour gérer de multiples cas et extraire des données à partir de structures complexes.

Au fur et à mesure que vous poursuivez votre apprentissage de Python, vous constaterez que le pattern matching complète la logique conditionnelle que vous avez apprise au Chapitre 8, en offrant une alternative élégante lorsque vous traitez plusieurs cas distincts, en particulier lorsque vous travaillez avec des données structurées. L’essentiel est de choisir le bon outil pour chaque situation : utilisez if-elif-else pour des conditions simples et de la logique booléenne, et privilégiez match-case lorsque vous vérifiez une valeur face à plusieurs possibilités ou lorsque vous travaillez avec des données structurées nécessitant une extraction basée sur des motifs.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai