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 :
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 correspondCommençons par un exemple simple qui illustre le concept fondamental :
# 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 foundDans 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 :
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 foundLes deux versions produisent le même résultat. Cependant, match-case offre plusieurs avantages :
- Intention plus claire : l’instruction
matchmontre explicitement que vous comparez une valeur à plusieurs possibilités - Moins de répétition : vous ne répétez pas le nom de la variable dans chaque comparaison
- Motifs plus puissants : comme nous allons le voir,
match-casepeut faire bien plus que de simples tests d’égalité - Meilleure lisibilité : pour des arbres de décision complexes,
match-caseest 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 :
# 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 completePuisque "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 :
# 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 kitchenCet 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 :
# 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: 403Le 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 :
# 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 eventsSans 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 :
# 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 soonVous 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 == :
# 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 enabledLes 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 » :
# 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 | :
# 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 action13.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 :
# 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: 201Le 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 :
# 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 detected13.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 :
# 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: saveLe 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 :
# 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éelleOutput:
Some other status codeMaintenant avec une variable de liaison :
# 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 receivedLa 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.
# 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 :
- Le sujet
pointest le tuple(3, 7) - Python vérifie chaque motif
casedans l’ordre - 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 - Le motif
(x, y)correspond parce que c’est un tuple de deux éléments - Python lie
xà3etyà7 - Le bloc
cases’exécute avec ces valeurs capturées
Voici un autre exemple montrant différents motifs de tuples :
# 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 255Cette 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 :
# 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 stepsLe 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 :
# 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.98Le 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.
# 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 grantedLe 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 :
# 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.
# 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: 42Cet 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 :
# 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 :
match subject:
case pattern if condition:
# Le code s’exécute uniquement si pattern correspond ET que condition est vraieVoyons un exemple simple :
# 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 grantedDans 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 :
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 :
# 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°CChaque 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 :
# 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% discountLe 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 :
# É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: SatisfactoryLa 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 :
# 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 privilegesCet 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.
# 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 :
# 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 timeout13.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 :
# 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.6Le 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.