0% ont trouvé ce document utile (0 vote)
0 vues12 pages

Cours Match Case Python

Le document présente la structure match ... case en Python, introduite dans la version 3.10, permettant de réaliser un filtrage par motifs. Il décrit la syntaxe de base, les types de motifs disponibles, ainsi que des exemples pratiques d'utilisation, tels que des calculatrices et la gestion d'erreurs HTTP. Des exercices de différents niveaux sont également fournis pour renforcer la compréhension de cette fonctionnalité.

Transféré par

cheikh kandji
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
0 vues12 pages

Cours Match Case Python

Le document présente la structure match ... case en Python, introduite dans la version 3.10, permettant de réaliser un filtrage par motifs. Il décrit la syntaxe de base, les types de motifs disponibles, ainsi que des exemples pratiques d'utilisation, tels que des calculatrices et la gestion d'erreurs HTTP. Des exercices de différents niveaux sont également fournis pour renforcer la compréhension de cette fonctionnalité.

Transféré par

cheikh kandji
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Cours Complet : match ...

case en Python
1. Introduction et Définition
La structure match ... case est une instruction de pattern matching (filtrage
par motifs) introduite en Python 3.10 (PEP 634, 635, 636). Elle permet de
comparer une valeur contre une série de motifs et d’exécuter du code lorsqu’un
motif correspond.

Pattern matching : Technique de programmation qui consiste à vérifier


si une structure de données correspond à un motif (pattern) donné, et à
extraire des informations de cette structure en cas de correspondance.

Différence clé avec if/elif/else : match ... case peut déstructurer (extraire
les parties) des structures de données complexes (listes, dictionnaires, objets)
en une seule opération, là où if nécessiterait plusieurs vérifications manuelles.

2. Syntaxe de Base
match expression:
case pattern_1:
# bloc exécuté si pattern_1 correspond
case pattern_2:
# bloc exécuté si pattern_2 correspond
case _:
# bloc par défaut (wildcard, optionnel)

Règles syntaxiques importantes : - match et case sont des mots-clés


réservés depuis Python 3.10 - Le bloc match doit être indenté - Chaque case est
suivi d’un motif puis de : - _ (underscore seul) est le motif “joker” qui correspond
à tout (équivalent de default ou else) - Pas de break nécessaire (contrairement
à switch en C/Java) — une seule branche s’exécute

3. Les Types de Patterns (Motifs)


3.1 Pattern Littéral (Literal Pattern)
Correspond à une valeur exacte.
def decrire_jour(jour):
match jour:
case 1:
return "Lundi"
case 2:
return "Mardi"
case 7:
return "Dimanche"
case _:
return "Numéro invalide"

print(decrire_jour(2)) # Mardi
print(decrire_jour(9)) # Numéro invalide

3.2 Pattern Variable (Capture Pattern)


Capture la valeur dans une variable pour l’utiliser dans le bloc.
match valeur:
case 0:
print("Zéro")
case x: # x capture n'importe quelle valeur
print(f"Valeur reçue : {x}")

Attention : case x: capture tout. Il doit être placé en dernier (ou


avant _), sinon les patterns suivants ne seront jamais atteints.

3.3 Pattern Or (|)


Plusieurs alternatives pour un même bloc.
match note:
case "A" | "B":
print("Excellent")
case "C" | "D":
print("Moyen")
case "E" | "F":
print("Insuffisant")
case _:
print("Note inconnue")

3.4 Pattern Séquence (Sequence Pattern)


Correspond à des listes, tuples, ou tout objet séquentiel.
# Tuple avec déstructuration
point = (3, 4)

match point:
case (0, 0):
print("Origine")
case (x, 0): # x capture la valeur, 0 est un littéral
print(f"Sur l'axe X à x={x}")
case (0, y):
print(f"Sur l'axe Y à y={y}")
case (x, y):
print(f"Point ({x}, {y})")
case _:
print("Format invalide")

# Liste avec longueur variable


match valeurs:
case [seul]: # liste à un élément
print(f"Un seul élément : {seul}")
case [premier, *reste]: # déstructuration avec reste
print(f"Premier : {premier}, Reste : {reste}")
case []:
print("Liste vide")

3.5 Pattern Mapping (Dictionnaire)


Correspond à des dictionnaires par leurs clés.
utilisateur = {"nom": "Alice", "age": 30, "ville": "Paris"}

match utilisateur:
case {"nom": str(nom), "age": int(age)}:
# Correspond si les clés "nom" et "age" existent et sont des st
r/int
print(f"{nom} a {age} ans")
case {"nom": nom}:
# Correspond si seule la clé "nom" existe
print(f"Nom connu : {nom}")
case {}:
print("Dictionnaire vide")
case _:
print("Ce n'est pas un dictionnaire")

Règle : Seules les clés mentionnées sont vérifiées. Le dictionnaire


peut avoir d’autres clés sans problème (sauf si vous utilisez **reste).

3.6 Pattern Classe / Dataclass


Correspond à des instances de classes et extrait leurs attributs.
from dataclasses import dataclass

@dataclass
class Point:
x: int
y: int

@dataclass
class Cercle:
centre: Point
rayon: float

forme = Cercle(Point(0, 0), 5)

match forme:
case Cercle(Point(0, 0), rayon):
print(f"Cercle centré à l'origine, rayon={rayon}")
case Cercle(centre, rayon):
print(f"Cercle en {centre}, rayon={rayon}")
case _:
print("Forme inconnue")

3.7 Pattern avec Guard (Clause de Garde)


Condition if supplémentaire après le pattern.
match age:
case n if n < 0:
print("Âge invalide")
case n if n < 18:
print("Mineur")
case n if n < 65:
print("Adulte")
case _:
print("Senior")

# Guard avec déstructuration


match liste:
case [x, y] if x == y:
print(f"Deux éléments identiques : {x}")
case [x, y]:
print(f"Deux éléments différents : {x} et {y}")

3.8 Pattern Sous-motif (Nested Patterns)


Patterns imbriqués pour structures complexes.
commande = {
"type": "paiement",
"data": {
"montant": 100,
"devise": "EUR",
"carte": {"numero": "1234", "cvv": "000"}
}
}

match commande:
case {
"type": "paiement",
"data": {
"montant": float(m),
"devise": "EUR",
"carte": {"numero": str(n)}
}
} if m > 0:
print(f"Paiement de {m} EUR par carte finissant par {n[-4:]}")
case _:
print("Commande invalide")

4. Exemples Complets et Progressifs


Exemple 1 : Calculatrice simple
def calculer(a, b, op):
match op:
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
if b == 0:
return "Erreur : division par zéro"
return a / b
case "**" | "^":
return a ** b
case _:
return f"Opération '{op}' non supportée"

print(calculer(10, 3, "*")) # 30
print(calculer(10, 0, "/")) # Erreur

Exemple 2 : Gestion d’erreurs HTTP


def traiter_reponse(status, body):
match (status, body): # Tuple à deux éléments
case (200, {"data": data}):
return f"Succès : {data}"
case (200, _):
return "Succès mais format inattendu"
case (404, {"message": msg}):
return f"Non trouvé : {msg}"
case (code, _) if 500 <= code < 600:
return f"Erreur serveur {code}"
case (code, _):
return f"Code inattendu : {code}"
print(traiter_reponse(200, {"data": [1, 2, 3]}))
# Succès : [1, 2, 3]

Exemple 3 : AST (Abstract Syntax Tree) simplifié


from dataclasses import dataclass
from typing import Union

@dataclass
class Nombre:
valeur: int

@dataclass
class Addition:
gauche: 'Expression'
droite: 'Expression'

@dataclass
class Multiplication:
gauche: 'Expression'
droite: 'Expression'

Expression = Union[Nombre, Addition, Multiplication]

def evaluer(expr: Expression) -> int:


match expr:
case Nombre(valeur=n):
return n
case Addition(gauche=g, droite=d):
return evaluer(g) + evaluer(d)
case Multiplication(gauche=g, droite=d):
return evaluer(g) * evaluer(d)
case _:
raise ValueError("Expression inconnue")

# Test : (1 + 2) * 3
expr = Multiplication(Addition(Nombre(1), Nombre(2)), Nombre(3))
print(evaluer(expr)) # 9

Exemple 4 : Parsing de commandes CLI


def parser_commande(args: list[str]):
match args:
case ["help"]:
return "Affiche l'aide"
case ["help", commande]:
return f"Aide sur la commande '{commande}'"
case ["copy", source, destination]:
return f"Copie de {source} vers {destination}"
case ["move", source, destination]:
return f"Déplacement de {source} vers {destination}"
case ["delete", *fichiers] if len(fichiers) > 0:
return f"Suppression de {len(fichiers)} fichier(s)"
case ["delete"]:
return "Erreur : aucun fichier à supprimer"
case [commande, *_]:
return f"Commande inconnue : {commande}"
case []:
return "Aucune commande fournie"

print(parser_commande(["copy", "[Link]", "[Link]"]))


# Copie de [Link] vers [Link]

5. Exercices
Exercice 1 : Niveau Débutant
Écrire une fonction decrire_animal(animal: str) qui retourne : - “Domestique”
pour “chat” ou “chien” - “Ferme” pour “vache”, “mouton”, “poule” - “Sauvage” pour
“lion”, “tigre”, “ours” - “Inconnu” sinon
# Votre code ici
def decrire_animal(animal: str) -> str:
...

Solution :
def decrire_animal(animal: str) -> str:
match animal:
case "chat" | "chien":
return "Domestique"
case "vache" | "mouton" | "poule":
return "Ferme"
case "lion" | "tigre" | "ours":
return "Sauvage"
case _:
return "Inconnu"

# Tests
print(decrire_animal("chat")) # Domestique
print(decrire_animal("poule")) # Ferme
print(decrire_animal("requin")) # Inconnu
Exercice 2 : Niveau Intermédiaire
Écrire une fonction analyser_coordonnees(point) qui prend un tuple de 2 ou 3
éléments : - (0, 0) → “Origine 2D” - (x, 0) → “Sur l’axe X en 2D” - (0, y) →
“Sur l’axe Y en 2D” - (x, y) → “Point 2D standard” - (x, y, z) → “Point 3D” -
Autre → “Format non supporté”
def analyser_coordonnees(point):
...

Solution :
def analyser_coordonnees(point):
match point:
case (0, 0):
return "Origine 2D"
case (x, 0):
return f"Sur l'axe X en 2D, x={x}"
case (0, y):
return f"Sur l'axe Y en 2D, y={y}"
case (x, y) if isinstance(x, (int, float)) and isinstance(y, (i
nt, float)):
return f"Point 2D ({x}, {y})"
case (x, y, z):
return f"Point 3D ({x}, {y}, {z})"
case _:
return "Format non supporté"

# Tests
print(analyser_coordonnees((0, 0))) # Origine 2D
print(analyser_coordonnees((5, 0))) # Sur l'axe X
print(analyser_coordonnees((1, 2, 3))) # Point 3D
print(analyser_coordonnees((1,))) # Format non supporté

Exercice 3 : Niveau Avancé — Expression Régulière Simplifiée


Créer un mini-évaluateur d’expressions arithmétiques représentées par des
dictionnaires imbriqués.
Format :
{"op": "add", "left": 5, "right": {"op": "mul", "left": 2, "right": 3}}
# Représente : 5 + (2 * 3) = 11

Opérations supportées : "add", "sub", "mul", "div". Les opérandes peuvent être
des nombres ou des sous-expressions.
def evaluer_expression(expr):
...

Solution :
def evaluer_expression(expr):
match expr:
case {"op": "add", "left": left, "right": right}:
return evaluer_expression(left) + evaluer_expression(right)
case {"op": "sub", "left": left, "right": right}:
return evaluer_expression(left) - evaluer_expression(right)
case {"op": "mul", "left": left, "right": right}:
return evaluer_expression(left) * evaluer_expression(right)
case {"op": "div", "left": left, "right": right}:
r = evaluer_expression(right)
if r == 0:
raise ValueError("Division par zéro")
return evaluer_expression(left) / r
case int(n) | float(n):
return n
case _:
raise ValueError(f"Expression invalide : {expr}")

# Test
expr = {
"op": "add",
"left": 5,
"right": {
"op": "mul",
"left": 2,
"right": 3
}
}
print(evaluer_expression(expr)) # 11

expr2 = {
"op": "sub",
"left": {"op": "mul", "left": 4, "right": 5},
"right": 10
}
print(evaluer_expression(expr2)) # 10

Exercice 4 : Expert — Validation de Schéma JSON


Écrire une fonction valider_config(config: dict) qui vérifie qu’une
configuration serveur est valide :
Règles : - Doit contenir "host" (str) et "port" (int entre 1 et 65535) -
Optionnellement "ssl" (bool) - Optionnellement "database" (dict avec "type"
valant "mysql" ou "postgres", et "name" str) - Si "debug" est True, afficher un
avertissement
Retourner "Valide", "Invalide : [raison]" ou "Avertissement : [msg]".
def valider_config(config: dict) -> str:
...

Solution :
def valider_config(config: dict) -> str:
match config:
case {
"host": str(host),
"port": int(port),
**reste
} if not (1 <= port <= 65535):
return f"Invalide : port {port} hors range [1-65535]"

case {
"host": str(host),
"port": int(port),
"database": {"type": str(db_type), "name": str(db_name)},
**reste
} if db_type not in ("mysql", "postgres"):
return f"Invalide : type de BDD '{db_type}' non supporté"

case {
"host": str(host),
"port": int(port),
"database": {"type": str(db_type), "name": str(db_name)},
"debug": True,
**reste
}:
return f"Avertissement : mode debug activé pour {host}:{por
t} avec {db_type}/{db_name}"

case {
"host": str(host),
"port": int(port),
"database": {"type": str(db_type), "name": str(db_name)},
**reste
}:
return "Valide"

case {
"host": str(host),
"port": int(port),
"debug": True,
**reste
}:
return f"Avertissement : mode debug activé pour {host}:{por
t}"

case {
"host": str(host),
"port": int(port),
**reste
}:
return "Valide"

case _:
return "Invalide : configuration mal formée"

# Tests
cfg1 = {"host": "localhost", "port": 8080}
print(valider_config(cfg1)) # Valide

cfg2 = {"host": "localhost", "port": 70000}


print(valider_config(cfg2)) # Invalide : port hors range

cfg3 = {"host": "localhost", "port": 3000, "database": {"type": "mysql"


, "name": "app"}, "debug": True}
print(valider_config(cfg3)) # Avertissement : mode debug...

cfg4 = {"host": "localhost", "port": 3000, "database": {"type": "mongo"


, "name": "app"}}
print(valider_config(cfg4)) # Invalide : type de BDD non supporté

6. Bonnes Pratiques et Pièges Courants


À faire
• Placer _ en dernier — c’est le cas par défaut
• Utiliser | pour regrouper les cas similaires plutôt que de dupliquer du
code
• Préférer les dataclasses pour le pattern matching sur objets complexes
• Utiliser les guards (if) pour des conditions qui dépassent la structure du
motif
À éviter
• Ne pas mélanger case x: et case _: sans réfléchir — case x: capture
tout et masque les patterns suivants
• Attention à l’ordre : Python teste les case de haut en bas, le premier
matchant est exécuté
• Ne pas confondre case [] et case list() — le premier vérifie une liste
vide, le second vérifie le type (syntaxe différente)

Différences avec switch d’autres langages


Caractéristique switch (C/Java) match ... case (Python)

Besoin de break Oui Non

Pattern complexe Non Oui

Déstructuration Non Oui

Guard clauses Non Oui

Fall-through Oui Non

7. Récapitulatif Visuel
match donnée: # ← Expression à tester
case [1, 2, 3]: # ← Littéral séquence
...
case [tete, *queue]: # ← Séquence + capture
...
case {"status": 200, "body": b}: # ← Mapping
...
case Point(x=0, y=0): # ← Classe + args nommés
...
case n if n < 0: # ← Variable + guard
...
case _: # ← Joker (default)
...

Prérequis : Python 3.10+


Documentation officielle : PEP 636 – Structural Pattern Matching: Tutorial
Bonne pratique !

Vous aimerez peut-être aussi