Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

L'instruction match / case (Python 3.10)

Les mots clés if, elif et else La boucle while


Accès rapide :
La vidéo
Introduction à l'utilisation de l'instruction « match / case »
Un petit préambule
Un premier exemple simple
Sélection multiple de valeurs
Utilisation du pattern matching
Correspondances avec des types de données
Correspondances avec des structures (des collections)
Travaux pratiques
Les énoncés
Les corrections

La vidéo

Cette vidéo vous présente la nouvelle instruction Python « match / case » qui arrive avec la nouvelle version de Python 3.10.


L'instruction match / case (Python 3.10 minimum).

Introduction à l'utilisation de l'instruction « match / case »

L'introduction de l'instruction match / case dans Python 3.10 marque une évolution significative dans le langage, offrant une alternative puissante et flexible aux traditionnelles structures conditionnelles comme if / elif / else. Cette nouveauté s'inspire des instructions similaires présentes dans d'autres langages, tels que switch / case en C, C++ ou encore Java, mais avec une approche unique adaptée à la philosophie de Python (notamment au travers du pattern matching, nous allons y revenir plus tard).

Un petit préambule

Avant de rentrer dans les détails de la syntaxe de cette instruction, je voulais revenir sur la notion de mot clé contextuel (concept introduit dans Python lors de l'ajout de cette nouvelle instruction ; Python 3.10).

Contrairement à des « mots-clés réservés » comme if ou for, les instructions match et case ne sont des mots-clés que dans certains contextes spécifiques. Cette particularité préserve la compatibilité ascendante du langage, évitant les conflits avec les anciens codes où match et case auraient pu être utilisés comme noms de variables ou de fonctions.

Dans l'exemple ci-dessous, les deux mots clé sont utilisés comme nom de variable et comme nom de fonction. Si vous exécutez ce code, vous vous apercevrez que cela fonctionne très bien : dans ce contexte, ils n'ont donc pas de sémantique particulière.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
match: bool = True
            

def case(param):
    print("Dans ce contexte, case est le nom de ma fonction")
    

if match:       # On test l'état de la variable booléenne
    case()      # On invoque notre fonction
Ici les mots match et case sont juste des identifiants sans sémantiques plus poussées
même si cela fonctionne très bien, cette possibilité est relative à la compatibilité ascendante pour d'éventuels anciens programmes. Dans vos nouveau code, merci de NE PAS JOUER avec cette possibilité et essayez de voir ces deux mots clé comme des mots clés réservés. Je pense que cela sera mieux ;-)

Un premier exemple simple

La structure match / case en Python est conçue pour faciliter la lecture du code et améliorer sa maintenabilité, en particulier dans les scénarios où de multiples conditions doivent être évaluées. Considérons un premier exemple ou nous allons obtenir une valeur aléatoire entière (entre 0 et 5) et afficher cette valeur en toutes lettres.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
from random import randint

random_value = randint(0, 5)

match random_value:
    case 0:
        print("Zéro")
    case 1:
        print("Un")
    case 2:
        print("Deux")
    case 3:
        print("Trois")
    case 4:
        print("Quatre")
    case 5:
        print("Cinq")
Un exemple simple d'utilisation de l'instruction match / case
bien que l'exemple précédent puisse être développé avec l'instruction if / elif / else, vous conviendrez aisément que l'approche match / case est plus élégante.

Parfois vous ne souhaitez pas traiter tous les cas de valeurs qu'une variable pourrait avoir et indiquer que ces valeurs ne sont pas considérées. Pour répondre à ce besoin, vous pouvez utiliser la branche spéciale case _: qui permet de considérer tous les autres cas. Voici une adaptation du programme précédent qui utilise cette possibilité : les valeurs supérieures à 5 seront traitées par cette branche.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
from random import randint

random_value = randint(0, 10)    # Cette fois-ci, je considère des valeurs entre 0 et 10 !!!

match random_value:
    case 0:
        print("Zéro")
    case 1:
        print("Un")
    case 2:
        print("Deux")
    case 3:
        print("Trois")
    case 4:
        print("Quatre")
    case 5:
        print("Cinq")
    case _:                      # On gère ici, tous les autres cas.
        print("Autre valeur")
Un exemple d'utilisation de la branche case _

Sélection multiple de valeurs

L'instruction match permet aussi de sélectionner plusieurs valeurs dans une même branche case : cela permet de réduire la quantité de code à produire dans certaines situation. Voici un exemple.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
from random import randint

random_value = randint(0, 10)
print("Random value =", random_value)

match random_value:
    case 0 | 1 | 2 | 4 | 8:
        print("Des valeurs que je veux traiter ici")
    case _:
        print("Traitement pour les autres valeurs")
Un exemple de sélection multiple

Bien entendu, l'instruction match sais gérer d'autres types que des numériques. Voici un autre exemple qui montre comment l'utiliser pour gérer des chaînes de caractères.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
import os

print("Welcome to SuperShell V1.0")

is_running = True
while is_running:
    cmd = input("Veuillez saisir une commande : ")

    match cmd:
        case "exit":
            is_running = False
        case "ls" | "dir":
            files = os.listdir(".")
            for file in files:
                print(file)
        case cmd if cmd[0:3] == "cd ":
            os.chdir(cmd[3:])
        case _:
            print("Commande", cmd, " inconnue")

print("Bye bye")
Un exemple d'utilisation du match avec des chaînes de caractères
cet exemple vous montre aussi qu'il est possible de mettre une condition (un if) dans une clause de sélection case afin de capturer plusieurs valeurs distinctes. Effectivement, le troisième case permet de traiter les commandes qui commencent par le préfixe "cd ".

Utilisation du pattern matching

L'ajout de l'instruction match / case à Python 3.10 a introduit une puissante capacité de pattern matching (correspondance de motifs) dans le langage. Cette fonctionnalité permet d'écrire des structures de contrôle plus expressives et flexibles.

Correspondances avec des types de données

Dorénavant, Python permet de combiner le pattern matching avec des vérifications de types. Par exemple, case str(): ou case int(): permet de vérifier si la valeur correspond à un type spécifique. Voici un exemple de code simpliste.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
str_value = input("Veuillez saisir une valeur numérique : ")
value = eval(str_value)

match value:
    case int():
        print("Valeur entière :", value)
    case float():
        print("Valeur flottante :", value)
    case complex():
        print("Valeur complexe :", value)
    case _:
        print("Ce n'est pas une valeur numérique")
Correspondances avec des types de données

Et voici un exemple d'utilisation de ce petit programme :

Veuillez saisir une valeur numérique : 3 + 2j
Valeur complexe : (3+2j)
j'en profite pour vous montrer que l'on peut manipuler des valeurs complexes (au sens mathématiques du terme). Dans l'exemple ci-dessus, 3 correspond à la partie réelle et 2j à la partie imaginaire. Mémorisez bien l'utilisation du caractère j pour indiquer la valeur de la partie imaginaire. En complément, voici comment déclarer une variable contenant une telle valeur : value = 3 + 2j.

Correspondances avec des structures (des collections)

Outre des valeurs littérales, vous pouvez aussi faire correspondre des structures de données complexes comme les listes, les tuples, ou les dictionnaires. Par exemple, case [x, y, z]: permet de reconnaître une liste à trois éléments et d'assigner chaque élément de la collection à une variable. Voici un exemple d'utilisation :

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
first_dict = {
    "id": 1,
    "sub_dict": {
        "part1": "value1",
        "part2": "value2"
    }
}

second_dict = {
    "id": 2,
    "part1": "valeur_1",
    "part2": "valeur_2"
}

for dictionary in [first_dict, second_dict, "autre"]:
    match dictionary:
        # On sélectionne un dictionnaire avec un "id" et un sous-dictionnaire.
        case {"id": identifier, "sub_dict": {"part1": part1, "part2": part2}}:
            print("Premier dictionnaire :", identifier, part1, part2)

        # On sélectionne un dictionnaire avec les champs "id", "part1" et "part2"
        case {"id": identifier, "part1": part1, "part2": part2}:
            print("Second dictonnaire :", identifier, part1, part2)

        case _:
            print("no match")
Correspondances avec des structures de données (dict)

Et voici les résultats affichés par ce programme :

Premier dictionnaire : 1 value1 value2
Second dictonnaire : 2 valeur_1 valeur_2
no match

Voici un dernier exemple de pattern matching permettant de sélectionner des listes avec des tailles distinctes. Notez bien que pour les deux premiers case, seules les listes contenant 10 en première valeurs seront considérées.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
str_value = input("Veuillez saisir une liste de valeurs numériques : ")
data = eval(str_value)


match data:
    case [10]:
        print("La liste ne contient que 10")
    case [10, a]:
        print(f"La liste contient 10 et {a}")
    case [10, a, b]:
        print(f"La liste contient 10 ainsi que {a} et {b}")
    case list():
        print("Une autre liste")
    case _:
        print("Ce n'est pas une liste")
Correspondances avec des structures de données (list)

Et voici les résultats affichés par ce programme :

Veuillez saisir une liste de valeurs numériques : [10, 20, 30]
La liste contient 10 ainsi que 20 et 30

Travaux pratiques

Les énoncés

Exercice 1 : écrivez une fonction hello qui prend une chaîne de caractères représentant une partie de la journée (par exemple, "matin", "après-midi", "soir") et renvoie un message de salutation approprié en utilisant l'instruction match / case.

Exercice 2 : créez une fonction display_contact qui prend un tuple représentant un contact sous la forme (nom, email) ou (nom, numéro) et renvoie un message indiquant le type de contact (email ou numéro de téléphone) en utilisant l'instruction match / case.

Exercice 2 : l'exercice consiste à écrire une fonction display_product qui utilise l'instruction match / case pour classifier des produits en fonction de leur type et de leur prix.

Les produits seront représentés par des dictionnaires contenant trois clés : type, name, et price. Les types possibles sont "électronique" et "livre". La fonction doit renvoyer une chaîne de caractères décrivant le produit.

Voici les règles de classification à appliquer :

Comme toujours, essayez de faire ces exercices sans regarder directement la correction ci-dessous. ;-)

Les corrections

Exercice 1 : voici ma proposition de correction.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
def hello(moment):
    match moment:
        case "matin":
            return "Bonjour !"
        case "après-midi":
            return "Bonne après-midi !"
        case "soir":
            return "Bonne soirée !"
        case _:
            return "Salut"


# On teste notre fonction
print(hello("matin"))   # Bonjour !
print(hello("soir"))    # Bonne soirée !
Correction de l'exercice 1

Exercice 2 : voici ma proposition de correction.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
def display_contact(contact):
    match contact:
        case (nom, email) if "@" in email:
            return f"{nom} a pour e-mail : {email}"
        case (nom, numero):
            return f"{nom} a pour numéro de téléphone : {numero}"

# Alice a pour e-mail : alice@example.com
print(display_contact(("Alice", "alice@example.com")))  

# Bob a pour numéro de téléphone : 123456789
print(display_contact(("Bob", "123456789")))
Correction de l'exercice 2
vous aurez remarqué que le premier bloc case et un cas particulier du second. Du coup, l'ordre des deux blocs case est important : Python, sélectionne le premier bloc qui « match » (qui correspond). Si vous les permutez, l'affichage sous forme d'un numéro de téléphone sera systématiquement produit. Je vous invite à faire ce test pour vous en convaincre.

Exercice 3 : voici ma proposition de correction.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
def display_product(a_product):
    name = a_product['name']
    match a_product:
        case {"type": "électronique", "price": prix} if prix > 500:
            return f"{name} est un équipement électronique coûteux"
        case {"type": "électronique", "price": _}:
            return f"{name} est un électronique abordable"
        case {"type": "livre", "price": prix} if prix < 20:
            return f"{name} est un livre abordable"
        case {"type": "livre", "price": _}:
            return f"{name} est un livre coûteux"
        case _:
            return "Type de produit inconnu"


product = {"type": "électronique", "name": "Smartphone", "price": 800}
# Smartphone est un équipement électronique coûteux
print(display_product(product))  

product = {"type": "livre", "name": "Python pour les Nuls", "price": 15}
# Python pour les Nuls est un livre abordable
print(display_product(product))
Correction de l'exercice 3


Les mots clés if, elif et else La boucle while