L'instruction match, aka PEP622

J’ai aucune idée de la meilleur mise en œuvre en Python (en Scheme, c’est une macro), cela dit je plussoie que c’est très utile.

Les exemples utilise la branche https://github.com/brandtbucher/cpython/tree/patma

Voici des usages que j’ai identifie:

Remplacer if / elif / else

Avant

value = input("Value: ")

if value == "one":
    print("Value is: 1")
elif value == "two":
    print("Value is: 2")
else:
    print("Value is unknown")

Après

value = input()

match value:
    case "one":
        print("Value is: 1")
    case "two":
        print("Value is: 2")
    case _:
        print("Unknown value")

Remplacer un dictionnaire de dispatch

Le dictionnaire de “dispatch” est une pattern pour éviter les if / elif / else en pagaille.

Avant


def print_one():
    print("Value is: 1")

def print_two():
    print("Value is: 2")

dispatch = dict(one=print_one, two=print_two)

value = input("value: ")

try:
    func = dispatch[value]
except KeyError:
    print("Unknown value...")
else:
    func()

Après

C’est la même chose pour le cas du if/elif/else

URL Route avec paramétrage

L’idée ici est de décider quelle route prendre en fonction de ce qu’on reçoit en HTTP en tant que chemin.

Avant

Django utilise / utilisait des regex (!) associés a des callables, flask un peu pareil en plus magicien, il utilise un langage spécifique embarque dans une chaîne de caractère qui est traduite en regex et qui permet de match (!) et capturer les paramètres.

En gros le code ressemble a:

def model_delete(request, model, pk):
    model_class = string_to_model(model)
    pk = int(pk)
    model.delete(pk)
    return redirect("/{}/list".format(model))

routes = [
    ["/<model>/create/", model_create],
    ["/<model>/delete/<pk>/", model_delete],
]

for pattern, callable in routes:
    if args := match(pattern, request.path):
        return callable(request, *args)
else:
    return 404

Après

def model_delete(request, model, pk):
    model_class = string_to_model_class(model)
    pk = int(pk)
    model_class.delete(pk)
    return redirect("/{}/list".format(model))

path = request.path.split("/")
match path:
    case [model, "create"]:
        model_create(request)
    case [model, "delete", pk]:
        model_delete(request, model, pk)