Python Pattern Matching im Admin Magazin #63¶

Die ursprünglich objektorientierte Programmiersprache Python soll in Version 3.10 ein neues Feature erhalten, das vor allem aus funktionalen Sprachen bekannt ist: Pattern-Matching. Die Änderung ist in der Python-Gemeinde umstritten und hat eine hitzige Debatte ausgelöst.
Pattern Matching ist eine Methode der Symbolverarbeitung, die anhand eines
Musters diskrete Strukturen oder Teilmengen identifiziert, z.B. Zeichenketten, Bäume oder Graphen. Dieses Verfahren findet sich in
funktionalen oder logischen Programmiersprachen, wo ein match
-Ausdruck
verwendet wird, um Daten auf der Grundlage ihrer Struktur zu verarbeiten,
z.B. in Scala,
Rust und
F#.
Eine match
-Anweisung nimmt einen Ausdruck und vergleicht ihn mit
aufeinanderfolgenden Mustern, die als ein oder mehrere Fälle angegeben sind.
Dies ist oberflächlich betrachtet ähnlich wie eine switch
-Anweisung in C,
Java oder JavaScript, aber viel leistungsfähiger.
Python 3.10 kann nun auch einen solchen match
-Ausdruck empfangen. Die
Implementierung ist im Python Enhancement Proposal PEP 634 beschrieben.
Weitere Informationen zu den Plänen finden sich in PEP 635 und PEP 636.
Wie das Pattern Matching in Python 3.10 funktionieren soll, zeigt dieses sehr
einfache Beispiel, bei dem ein Wert mit mehreren Literalen verglichen wird:
def http_error(status):
match status:
case 400:
return "Bad request"
case 401:
return "Unauthorized"
case 403:
return "Forbidden"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something else"
Im letzten Fall der match
-Anweisung fungiert ein Unterstrich _
als
Platzhalter, der alles abfängt. Dies hat unter Entwicklern zu Irritationen
geführt, da in Python üblicherweise ein Unterstrich vor Variablennamen verwendet
wird, um diese für den internen Gebrauch zu deklarieren. Obwohl Python nicht so
streng zwischen privaten und öffentlichen Variablen unterscheidet wie Java, ist
dies dennoch eine weit verbreitete Konvention, die auch im Style Guide for
Python Code PEP 8 spezifiziert ist.
Die vorgeschlagene match
-Anweisung kann jedoch nicht nur Muster prüfen,
d.h. eine Übereinstimmung zwischen dem Wert einer Variablen
und einem gegebenen Muster feststellen, sondern auch die Variablen, die dem
gegebenen Muster entsprechen, neu binden.
Das führt dazu, dass wir es in Python plötzlich mit Schrödinger-Konstanten zu
tun haben, die nur so lange konstant bleiben, bis wir sie in einer
match
-Anweisung näher betrachten. Das folgende Beispiel soll dies
verdeutlichen:
NOT_FOUND = 404
retcode = 200
match retcode:
case NOT_FOUND:
print("not found")
print(f"Current value of {NOT_FOUND=}")
Das Ergebnis ist die folgende Ausgabe:
not found
Current value of NOT_FOUND=200
Dieses Verhalten führt zu scharfer Kritik an dem Vorschlag von erfahrenen Python-Entwicklern wie Brandon Rhodes, Autor von „Foundations of Python Network Programming“:
„Wenn diese schlecht durchdachte Funktion wirklich zu Python hinzugefügt wird, verlieren wir einen Grundsatz, den ich meinen Studenten immer beigebracht habe: ‚Wenn du eine undokumentierte Konstante siehst, kannst du sie immer benennen, ohne die Bedeutung des Codes zu verändern.‘ Das Substitutionsprinzip, gelernt in Algebra? Es wird nicht mehr gelten.“
— Brandon Rhodes am 12. Februar 2021, 2.55 Uhr auf Twitter [1]
Viele langjährige Python-Entwickler meckern jedoch nicht nur über das strukturelle Pattern-Matching, das in Python 3.10 kommen soll. Sie bedauern generell die Entwicklung der letzten Jahre, in denen immer mehr syntaktischer Zucker über die Sprache gestreut wurde. Ursprüngliche Prinzipien, wie sie im Zen of Python PEP 20 niedergelegt sind, würden vergessen und die funktionale Stabilität ginge verloren.
Obwohl Python mit den Python Enhancement Proposals (PEPs) PEP 0 einen ausgefeilten Prozess definiert hat, mit dem die Weiterentwicklung von Python kollaborativ gesteuert werden kann, gibt es immer wieder Kritik auf Twitter und anderen sozialen Medien, so auch jetzt beim Structural Pattern Matching. Tatsächlich wurde das Thema in der Python-Community bereits intensiv diskutiert. Der Python Steering Council [2] empfahl die Annahme der Proposals bereits im Dezember 2020. Dennoch ist das Thema erst mit der Verabschiedung der Proposals so richtig hochgekocht. Der Grund dafür ist sicherlich die Größe und Vielfalt der Python-Gemeinschaft. Die meisten Programmierer*innen sind wahrscheinlich nur an Diskussionen über Erweiterungen interessiert, die ihre eigenen Probleme lösen. Die anderen Entwicklungen werden übersehen, bis die PEPs angenommen sind. Dies ist wahrscheinlich der Fall beim strukturellen Mustervergleich. Es eröffnet Lösungen für Probleme, die vorher in Python kaum möglich waren. Zum Beispiel können Data Scientists damit passende Parser und Compiler schreiben, für die sie bisher auf funktionale oder logische Programmiersprachen zurückgreifen mussten.
Mit der Verabschiedung des PEP ist die Diskussion nun in die breitere
Python-Gemeinschaft getragen worden. Brett Cannon, Mitglied des Python Steering
Council, wies übrigens in einem Interview [3] darauf hin, dass das letzte Wort
noch nicht gesprochen sei: Bis zur ersten Beta-Version sei noch Zeit für
Änderungen, falls Probleme im praktisch genutzten Code auftreten. Er stellte
auch in Aussicht, dass die Bedeutung von _
noch einmal geändert werden
könnte.
Vielleicht bleiben wir also von Schrödingers Konstanten verschont.