Het patroonmatching mechanisme is geïntroduceerd in Python 3.10 onder de naam Structural Pattern Matching en is gerealiseerd met behulp van de match-case constructie. Dit hulpmiddel stelt gebruikers in staat om elegant en beknopt complexe datastructuren te analyseren door ze te vergelijken met sjablonen.
In veel functionele talen (bijvoorbeeld Haskell, Scala) wordt patroonmatching al lang beschouwd als een handige manier om de logica te vertakken op basis van datastructuur. Python had lange tijd geen dergelijk mechanisme en gebruikte if-elif-else-ketens of unpacking.
Complexe geneste datastructuren (woordenboeken, lijsten, objecten) vereisen vaak meerdere controles op types, waarden en structuren, wat leidt tot rommelige code met veel voorwaarden.
match-case biedt een declaratieve en leesbare manier om verschillende gegevensverwerkingsscenario's te beschrijven rekening houdend met type en structuur zonder een opeenhoping van voorwaarden.
def process(event): match event: case {"type": "click", "x": x, "y": y}: return f"Klik op ({x}, {y})" case [command, *args]: return f"Commando: {command}, args: {args}" case _: return "Onbekende gebeurtenis" print(process({"type": "click", "x": 2, "y": 5})) # Klik op (2, 5) print(process(["RUN", 1, 2, 3])) # Commando: RUN, args: [1, 2, 3]
Matcht match-case alleen op waarde? Nee. Het matchen kan plaatsvinden op basis van structuur, type, unpacking van collecties en zelfs eigenschappen van objecten (indien speciale methoden match_args zijn opgegeven).
Beïnvloedt de volgorde van case in match? Ja. De analyse gebeurt van boven naar beneden; het eerste passende sjabloon treedt in werking. Latere cases worden niet gecontroleerd.
Is het mogelijk om samengestelde klassen te matchen? Ja, als de klasse de methoden match_args en/of getitem implementeert. Dan kan patroonmatching waarden van velden extraheren.
class Point: __match_args__ = ("x", "y") def __init__(self, x, y): self.x = x self.y = y def where(obj): match obj: case Point(x, y): return f"Point op {x}, {y}" case _: return "Onbekend" print(where(Point(1, 2))) # Point op 1, 2
Voordelen:
Negatieve case: Ontwikkelaars gebruikten match-case zelfs voor simpele booleaanse splitsingen, wat de code alleen maar ingewikkelder maakte. Voordelen: geleerd nieuwe functie. Nadelen: verloren leesbaarheid en verhoogd aantal fouten.
Positieve case: In een applicatie met een groot aantal gebeurtenissen en geneste structuren (bijvoorbeeld een grafparser) stelde match-case hen in staat om omvangrijke if-elif te vermijden en de parsing te centraliseren. Voordelen: leesbaarheid is toegenomen, aantal bugs is afgenomen. Nadelen: het vereiste training van het team om met de nieuwe constructie te werken.