Struktureller Musterabgleich in Python

Mehvish Ashiq 10 Oktober 2023
  1. Einführung in den strukturellen Musterabgleich und seine Bedeutung
  2. Verwenden Sie den strukturellen Musterabgleich in Python
Struktureller Musterabgleich in Python

Vor Python 3.10 hatten wir keine eingebaute Möglichkeit, den strukturellen Musterabgleich zu verwenden, der in anderen Programmiersprachen als switch-case bezeichnet wird. Ab der Version Python 3.10 können wir die Anweisung match ... case nicht verwenden, um die Anweisung switch ... case zu emulieren.

Dieses Tutorial stellt den strukturellen Musterabgleich und seine Bedeutung in Python vor. Es verwendet auch verschiedene Muster, um die Verwendung der Anweisung match ... case zu demonstrieren.

Einführung in den strukturellen Musterabgleich und seine Bedeutung

Ab Anfang 2021 konnten wir das Schlüsselwort match in veröffentlichten Python-Versionen kleiner oder gleich 3.9 nicht verwenden. Damals waren wir es gewohnt, switch ... case mit einem Wörterbuch oder verschachtelten if/elif/else-Anweisungen zu simulieren.

Aber Python 3.10 hat eine neue Funktion eingeführt, die als struktureller Musterabgleich bekannt ist (match ... case-Anweisung). Es entspricht einer switch ... case-Anweisung, wie wir sie in Java, C++ und vielen anderen Programmiersprachen haben.

Diese neue Funktion hat es uns ermöglicht, einfache, leicht lesbare und minimal anfällige Anweisungen zur Fehlerflusskontrolle zu schreiben.

Verwenden Sie den strukturellen Musterabgleich in Python

Der strukturelle Musterabgleich wird als switch ... case-Anweisung verwendet und ist leistungsfähiger als diese. Wie? Sehen wir uns unten einige Beispiele an, um ihre Verwendung in verschiedenen Situationen zu erfahren.

Grundlegende Verwendung der Anweisung match ... case

Beispielcode:

# >= Python 3.10
colour = "blue"
match colour:
    case "green":
        print("The specified colour is green")
    case "white":
        print("Wow, you've picked white")
    case "green":
        print("Great, you are going with green colour")
    case "blue":
        print("Blue like sky...")

AUSGANG:

Blue like sky...

Hier haben wir zunächst eine Variable Farbe, die Blau enthält. Dann verwenden wir das Schlüsselwort match, das den Wert der Variable color mit verschiedenen angegebenen Fällen abgleicht, wobei jeder Fall mit dem Schlüsselwort case beginnt, gefolgt von einem Muster, das wir vergleichen oder überprüfen möchten.

Das Muster kann eines der folgenden sein:

  • wörtliches Muster
  • Erfassungsmuster
  • Platzhaltermuster
  • konstantes Wertmuster
  • Sequenzmuster
  • Zuordnungsmuster
  • Klassenmuster
  • ODER-Muster
  • Walrossmuster

Die Anweisung match ... case führt den Code nur unter dem ersten übereinstimmenden case aus.

Was ist, wenn kein Fall zugeordnet ist? Wie wird der Benutzer davon erfahren? Dafür können wir einen standardmäßigen Fall wie folgt haben.

Beispielcode:

# >= Python 3.10
colour = "yellow"
match colour:
    case "green":
        print("The specified colour is green")
    case "white":
        print("Wow, you've picked white")
    case "green":
        print("Great, you are going with green colour")
    case "blue":
        print("Blue like sky...")
    case other:
        print("No match found!")

AUSGANG:

No match found!

Verwenden Sie match ... case, um Datenstrukturen zu erkennen und zu dekonstruieren

Beispielcode:

# >= Python 3.10
student = {"name": {"first": "Mehvish", "last": "Ashiq"}, "section": "B"}

match student:
    case {"name": {"first": firstname}}:
        print(firstname)

AUSGANG:

Mehvish

Im obigen Beispiel ist der strukturelle Musterabgleich in den folgenden zwei Codezeilen in Aktion:

# >= Python 3.10
match student:
    case {"name": {"first": firstname}}:

Wir verwenden die Anweisung match ... case, um den Vornamen des Studenten zu finden, indem wir ihn aus der Datenstruktur student extrahieren. Hier ist der Schüler ein Wörterbuch, das die Informationen des Schülers enthält.

Die case-Zeile gibt unser Muster an, um dem student zu entsprechen. Unter Berücksichtigung des obigen Beispiels suchen wir nach einem Wörterbuch mit dem Schlüssel Name, dessen Wert ein neues Wörterbuch ist.

Dieses verschachtelte Wörterbuch enthält einen "first"-Schlüssel, dessen Wert an die firstname-Variable gebunden ist. Schließlich verwenden wir die Variable firstname, um den Wert auszudrucken.

Wir haben das Abbildungsmuster hier gelernt, wenn Sie es genauer beobachten. Wie? Das Zuordnungsmuster sieht wie folgt aus: {"student": s, "emails": [*es]}, was der Zuordnung mit mindestens einem Satz angegebener Schlüssel entspricht.

Wenn alle Untermuster mit ihren entsprechenden Werten übereinstimmen, dann bindet es, was auch immer ein Untermuster während des Abgleichs mit Werten bindet, die den Schlüsseln entsprechen. Wenn wir das Erfassen der zusätzlichen Elemente zulassen möchten, können wir am Ende des Musters **rest hinzufügen.

Verwenden Sie match ... case mit dem Capture Pattern & Sequence Pattern

Beispielcode:

# >= Python 3.10
def sum_list_of_numbers(numbers):
    match numbers:
        case []:
            return 0
        case [first, *rest]:
            return first + sum_list_of_numbers(rest)


sum_list_of_numbers([1, 2, 3, 4])

AUSGANG:

10

Hier verwenden wir die rekursive Funktion, um das Erfassungsmuster zu verwenden, um die Übereinstimmung mit dem angegebenen Muster zu erfassen und an den Namen zu binden.

In diesem Codebeispiel gibt der erste case als Summe 0 zurück, wenn er mit einer leeren Liste übereinstimmt. Der zweite Fall verwendet das Sequenzmuster mit zwei Erfassungsmustern, um die Listen mit einem von mehreren Elementen/Elementen abzugleichen.

Hier wird das erste Element in einer Liste erfasst und an den ersten Namen gebunden, während das zweite Erfassungsmuster, *rest, die Entpackungssyntax verwendet, um eine beliebige Anzahl von Elementen/Elementen abzugleichen.

Beachten Sie, dass der rest an die Liste gebunden ist, die alle Elemente/Elemente von Zahlen enthält, mit Ausnahme des ersten. Um die Ausgabe zu erhalten, rufen wir die Funktion sum_list_of_numbers() auf, indem wir eine Liste von Zahlen wie oben angegeben übergeben.

Verwenden Sie match ... case mit dem Wildcard-Muster

Beispielcode:

# >= Python 3.10
def sum_list_of_numbers(numbers):
    match numbers:
        case []:
            return 0
        case [first, *rest]:
            return first + sum_list_of_numbers(rest)
        case _:
            incorrect_type = numbers.__class__.__name__
            raise ValueError(
                f"Incorrect Values. We Can only Add lists of numbers,not {incorrect_type!r}"
            )


sum_list_of_numbers({"1": "2", "3": "4"})

AUSGANG:

ValueError: Incorrect Values. We Can only Add lists of numbers, not 'dict'

Wir haben das Konzept der Verwendung des Wildcard-Musters gelernt, während wir die grundlegende Verwendung der Anweisung match ... case gelernt haben, aber den Begriff des Wildcard-Musters dort nicht eingeführt. Stellen Sie sich ein Szenario vor, in dem die ersten beiden Fälle nicht übereinstimmen und wir als letzten Fall ein Catchall-Muster benötigen.

Beispielsweise möchten wir einen Fehler auslösen, wenn wir anstelle einer Liste eine andere Art von Datenstruktur erhalten. Hier können wir _ als Platzhaltermuster verwenden, das mit allem übereinstimmt, ohne an den Namen gebunden zu sein. Wir fügen in diesem letzten Fall eine Fehlerbehandlung hinzu, um den Benutzer zu informieren.

Was sagen Sie? Passt unser Muster gut dazu? Testen wir es, indem wir die Funktion sum_list_of_numbers() aufrufen, indem wir eine Liste von String-Werten wie folgt übergeben:

sum_list_of_numbers(["1", "2", "3", "4"])

Es wird den folgenden Fehler erzeugen:

TypeError: can only concatenate str (not "int") to str

Wir können also sagen, dass das Muster immer noch nicht narrensicher genug ist. Warum? Weil wir eine Datenstruktur vom Typ Liste an die Funktion sum_list_of_numbers() übergeben, aber Werte vom Typ String haben, nicht wie erwartet den Typ Int.

Lesen Sie den folgenden Abschnitt, um zu erfahren, wie Sie es beheben können.

Verwenden Sie match ... case mit dem Klassenmuster

Beispielcode:

# >= Python 3.10
def sum_list_of_numbers(numbers):
    match numbers:
        case []:
            return 0
        case [int(first), *rest]:
            return first + sum_list_of_numbers(rest)
        case _:
            raise ValueError(f"Incorrect values! We can only add lists of numbers")


sum_list_of_numbers(["1", "2", "3", "4"])

AUSGANG:

ValueError: Incorrect values! We can only add lists of numbers

Der Basisfall (der erste Fall) gibt 0 zurück; Daher funktioniert das Summieren nur für die Typen, die wir mit Zahlen addieren können. Beachten Sie, dass Python nicht weiß, wie man Textzeichenfolgen und Zahlen hinzufügt.

Wir können also das Klassenmuster verwenden, um unser Muster so einzuschränken, dass es nur mit ganzen Zahlen übereinstimmt. Das Klassenmuster ähnelt dem Zuordnungsmuster, entspricht aber den Attributen anstelle der Schlüssel.

Verwenden Sie match ... case mit dem ODER-Muster

Beispielcode:

# >= Python 3.10
def sum_list_of_numbers(numbers):
    match numbers:
        case []:
            return 0
        case [int(first) | float(first), *rest]:
            return first + sum_list_of_numbers(rest)
        case _:
            raise ValueError(f"Incorrect values! We can only add lists of numbers")

Angenommen, wir möchten, dass die Funktion sum_list_of_numbers() für eine Liste von Werten funktioniert, unabhängig davon, ob es sich um Werte vom Typ Int oder Float handelt. Wir verwenden das ODER-Muster, dargestellt durch ein Pipe-Zeichen (|).

Der obige Code muss den ValueError auslösen, wenn die angegebene Liste andere Werte als Werte vom Typ int oder float enthält. Lassen Sie uns unter Berücksichtigung aller drei Szenarien testen.

Test 1: Übergeben Sie eine Liste mit Werten vom Typ int:

sum_list_of_numbers([1, 2, 3, 4])  # output is 10

Test 2: Übergeben Sie eine Liste mit Float-Werten:

sum_list_of_numbers([1.0, 2.0, 3.0, 4.0])  # output is 10.0

Test 3: Führen Sie eine Liste mit einem beliebigen anderen Typ außer den Typen int und float durch:

sum_list_of_numbers(["1", "2", "3", "4"])
# output is ValueError: Incorrect values! We can only add lists of numbers

Wie Sie sehen können, funktioniert die Funktion sum_list_of_numbers() aufgrund der Verwendung des OR-Musters sowohl für int- als auch für Float-Werte.

Verwenden Sie match ... case mit dem Literal Pattern

Beispielcode:

# >= Python 3.10
def say_hello(name):
    match name:
        case "Mehvish":
            print(f"Hi, {name}!")
        case _:
            print("Howdy, stranger!")


say_hello("Mehvish")

AUSGANG:

Hi, Mehvish!

Dieses Beispiel verwendet ein Literalmuster, das mit dem Literalobjekt übereinstimmt, beispielsweise eine explizite Zahl oder Zeichenfolge, wie wir es bereits getan haben, als wir die grundlegende Verwendung der Anweisung match ... case gelernt haben.

Es ist die grundlegendste Art von Muster und lässt uns eine switch ... case-Anweisung ähnlich wie Java, C++ und andere Programmiersprachen simulieren. Sie können diese Seite besuchen, um mehr über alle Muster zu erfahren.

Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook