Python Pattern Matching im Linux-Magazin 05/2021

Die ursprünglich objektorientierte Programmiersprache Python soll in der Version 3.10 ein neues Feature erhalten, das vor allem aus funktionalen Sprachen bekannt ist: Pattern Matching. Die Änderung ist in der Python-Community umstritten und hat eine hitzige Debatte ausgelöst.

Pattern Matching ist ein Verfahren zur Symbolverarbeitung, das anhand eines Musters diskrete Strukturen oder Teilmengen, z.B. Zeichenketten, Bäume oder Graphen, identifiziert. Dieses Verfahren findet sich in funktionalen oder logischen Programmiersprachen, in denen ein Match-Ausdruck verwendet wird, um Daten basierend auf 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 gesehen ähnlich wie eine switch-Anweisung in C, Java oder JavaScript, aber viel mächtiger.

Python 3.10 soll nun auch einen solchen Match-Ausdruck erhalten. Die Implementierung ist im PEP (Python Enhancement Proposal) 634 beschrieben [1]. Weitere Informationen zu den Plänen finden Sie in PEP 635 [2] und PEP 636 [3]. 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 für Irritationen gesorgt, da in Python üblicherweise ein Unterstrich vor Variablennamen verwendet wird, um diese für den internen Gebrauch zu deklarieren. Zwar wird in Python nicht so streng zwischen privaten und öffentlichen Variablen unterschieden wie in Java, aber es handelt sich dennoch um eine sehr weit verbreitete Konvention, die auch im Style Guide for Python Code [4] festgelegt 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 auf das gegebene Muster passen, neu binden.

Das führt dazu, dass wir es in Python plötzlich mit Schrödingers 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=}")

Dies führt zu der folgenden Ausgabe:

not found
Current value of NOT_FOUND=200

Dieses Verhalten führt zu harscher 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 ein Prinzip, das 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, 14:55 auf Twitter [5]

Viele langjährige Python-Entwickler murren aber 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 von Python [6] niedergelegt sind, würden dabei vergessen und die funktionale Stabilität ginge verloren.

Obwohl Python mit den Python Enhancement Proposals (PEPs) [7] einen ausgefeilten Prozess definiert hat, mit dem die Weiterentwicklung von Python kollaborativ gesteuert werden kann, gibt es auf Twitter und anderen sozialen Medien immer wieder Kritik, so auch jetzt beim Structural Pattern Matching. Tatsächlich wurde das Thema in der Python-Community bereits intensiv diskutiert. Der Python Steering Council [8] empfahl, die Vorschläge bereits im Dezember 2020 zu verabschieden. Dennoch ist das Thema erst mit der Verabschiedung der Proposals so richtig aufgekocht. Der Grund dafür ist sicherlich die Größe und Vielfalt der Python-Community. Die meisten Programmierer 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 erlaubt es Datenwissenschaftlern, passende Parser und Compiler zu 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, ein Mitglied des Python Steering Councils, wies übrigens in einem Interview [9] darauf hin, dass das letzte Wort noch nicht gesprochen ist: Bis zur ersten Betaversion sei noch Zeit für Änderungen, falls Probleme im praktisch genutzten Code auftreten. Er stellte auch in Aussicht, die Bedeutung von _ noch einmal zu ändern.

Vielleicht bleiben uns also Schrödingers Konstanten erspart.


[1]PEP 634: Specification
[2]PEP 635: Motivation and Rationale
[3]PEP 636: Tutorial
[4]https://pep8.org/#descriptive-naming-styles
[5]@brandon_rhodes
[6]PEP 20 – The Zen of Python
[7]Index of Python Enhancement Proposals (PEPs)
[8]Python Steering Council
[9]Python Bytes Episode #221