Python & AI Tutorials Logo
Python Programmierung

13. Entscheidungen treffen mit match und case (Strukturelles Pattern Matching)

Wenn Ihr Programm Entscheidungen auf Basis mehrerer möglicher Werte oder Muster treffen muss, haben Sie bereits gelernt, if-elif-else-Ketten aus Kapitel 8 zu verwenden. Python 3.10 führte eine leistungsstarke Alternative namens strukturelles Pattern Matching ein, die match- und case-Anweisungen verwendet. Dieses Feature bietet eine sauberere, ausdrucksstärkere Möglichkeit, komplexe Entscheidungsszenarien zu handhaben.

Pattern Matching geht über einfache Wertvergleiche hinaus. Es erlaubt Ihnen, gegen die Struktur und Form von Daten zu matchen, Werte aus komplexen Objekten zu extrahieren und Mehrfachentscheidungen in einer besser lesbaren Form auszudrücken. Während if-elif-else-Ketten für viele Situationen perfekt funktionieren, glänzen match-case-Anweisungen, wenn Sie mit mehreren klar unterscheidbaren Fällen zu tun haben, besonders bei strukturierten Daten.

13.1) match- und case-Anweisungen einführen (aufbauend auf if-elif aus Kapitel 8)

13.1.1) Die Grundstruktur von match-case

Eine match-Anweisung untersucht einen Wert (das sogenannte Subject) und vergleicht ihn mit einem oder mehreren Mustern, die in case-Klauseln definiert sind. Wenn ein Muster passt, führt Python den Codeblock aus, der zu diesem Fall gehört.

Hier ist die Grundstruktur:

python
match subject:
    case pattern1:
        # Code, der ausgeführt wird, wenn pattern1 passt
    case pattern2:
        # Code, der ausgeführt wird, wenn pattern2 passt
    case pattern3:
        # Code, der ausgeführt wird, wenn pattern3 passt

Beginnen wir mit einem einfachen Beispiel, das das grundlegende Konzept demonstriert:

python
# Einfacher Handler für HTTP-Statuscodes
status_code = 404
 
match status_code:
    case 200:
        print("Success: Request completed")
    case 404:
        print("Error: Page not found")
    case 500:
        print("Error: Server error")

Output:

Error: Page not found

In diesem Beispiel untersucht die match-Anweisung status_code (das Subject). Python prüft jedes case-Muster der Reihe nach. Wenn es feststellt, dass status_code gleich 404 ist, führt es den entsprechenden Codeblock aus und beendet anschließend die match-Anweisung. Die verbleibenden Fälle werden nicht mehr geprüft.

13.1.2) Wie sich match-case von if-elif-else unterscheidet

Sie fragen sich vielleicht: „Könnte ich das nicht mit if-elif-else schreiben?“ Ja, das könnten Sie:

python
status_code = 404
 
if status_code == 200:
    print("Success: Request completed")
elif status_code == 404:
    print("Error: Page not found")
elif status_code == 500:
    print("Error: Server error")

Output:

Error: Page not found

Beide Versionen erzeugen das gleiche Ergebnis. Allerdings bietet match-case mehrere Vorteile:

  1. Klarere Absicht: Die match-Anweisung zeigt explizit, dass Sie einen Wert gegen mehrere Möglichkeiten prüfen
  2. Weniger Wiederholung: Sie wiederholen den Variablennamen nicht in jedem Vergleich
  3. Leistungsfähigere Muster: Wie wir sehen werden, kann match-case viel mehr als einfache Gleichheitsprüfungen
  4. Bessere Lesbarkeit: Bei komplexen Entscheidungsbäumen ist match-case oft leichter zu verstehen

13.1.3) Wenn kein Muster passt

Was passiert, wenn keines der Muster passt? Die match-Anweisung wird einfach beendet, ohne einen Case-Block auszuführen:

python
# Benutzerrollen-Prüfer
user_role = "guest"
 
match user_role:
    case "admin":
        print("Full system access granted")
    case "moderator":
        print("Content management access granted")
    case "editor":
        print("Editing access granted")
 
print("Role check complete")

Output:

Role check complete

Da "guest" auf keines der Muster passt, wird kein Case-Block ausgeführt. Das Programm läuft mit dem Code nach der match-Anweisung weiter. Dieses Verhalten ist wichtig zu verstehen—anders als bei if-elif-else-Ketten, bei denen Sie eine abschließende else-Klausel hinzufügen können, um alle übrigen Fälle abzufangen, wird eine einfache match-Anweisung ohne Catch-all-Muster stillschweigend nichts tun, wenn kein Muster passt.

13.1.4) Praktisches Beispiel: Menüauswahlsystem

Bauen wir ein vollständigeres Beispiel, das die Klarheit von match-case bei der Behandlung von Benutzerentscheidungen zeigt:

python
# Restaurant-Bestellsystem
menu_choice = 3
 
match menu_choice:
    case 1:
        item = "Caesar Salad"
        price = 8.99
        print(f"You ordered: {item} - ${price}")
    case 2:
        item = "Grilled Chicken"
        price = 14.99
        print(f"You ordered: {item} - ${price}")
    case 3:
        item = "Vegetable Pasta"
        price = 12.99
        print(f"You ordered: {item} - ${price}")
    case 4:
        item = "Chocolate Cake"
        price = 6.99
        print(f"You ordered: {item} - ${price}")
 
print("Order submitted to kitchen")

Output:

You ordered: Vegetable Pasta - $12.99
Order submitted to kitchen

Dieses Beispiel zeigt, dass jeder Case mehrere Anweisungen enthalten kann. Wenn menu_choice auf 3 passt, führt Python alle drei Zeilen in diesem Case-Block aus: das Zuweisen von item, das Zuweisen von price und das Ausgeben der Bestellbestätigung.

13.2) Das _-Wildcard, Literal Patterns und Multiple Patterns verwenden

13.2.1) Das Wildcard-Muster: Alles andere abfangen

Der Unterstrich _ ist ein spezielles Muster, das auf alles passt. Er wird typischerweise als letzter Case verwendet, um alle Werte zu behandeln, die nicht auf vorherige Muster gepasst haben—ähnlich wie eine abschließende else-Klausel in einer if-elif-else-Kette:

python
# Handler für HTTP-Statuscodes mit Standardfall
status_code = 403
 
match status_code:
    case 200:
        print("Success: Request completed")
    case 404:
        print("Error: Page not found")
    case 500:
        print("Error: Server error")
    case _:
        print(f"Unhandled status code: {status_code}")

Output:

Unhandled status code: 403

Das _-Muster fungiert als Catch-all. Da 403 auf keinen der spezifischen Cases passt, passt das Wildcard-Muster und führt seinen Block aus. Das Wildcard-Muster passt auf jeden Wert, daher sollte es immer zuletzt stehen—Cases danach würden nie ausgeführt.

Hier ist, warum das Wildcard-Muster in der Praxis nützlich ist:

python
# Terminplaner für Wochentage
day = "Saturday"
 
match day:
    case "Monday":
        print("Team meeting at 9 AM")
    case "Wednesday":
        print("Project review at 2 PM")
    case "Friday":
        print("Weekly report due")
    case _:
        print(f"{day}: No scheduled events")

Output:

Saturday: No scheduled events

Ohne das Wildcard-Muster würde die match-Anweisung, wenn day "Saturday", "Sunday" oder ein anderer Wert wäre, stillschweigend ohne Ausgabe enden. Das Wildcard stellt sicher, dass Sie unerwartete oder nicht spezifizierte Fälle sauber behandeln.

13.2.2) Literal Patterns: Bestimmte Werte matchen

Literal Patterns matchen exakte Werte. Wir haben sie bereits verwendet—Zahlen, Strings und boolesche Werte sind alles Literal Patterns:

python
# Ampelsteuerung
light_color = "yellow"
 
match light_color:
    case "green":
        print("Go")
    case "yellow":
        print("Caution: Light changing soon")
    case "red":
        print("Stop")
    case _:
        print("Invalid light color")

Output:

Caution: Light changing soon

Sie können Literal Patterns unterschiedlicher Typen verwenden, und match vergleicht sowohl den Wert als auch seinen Typ:

python
# Konfigurationsvalidator (mit unterschiedlichen Literal-Typen)
setting_value = True
 
match setting_value:
    case True:        # boolesches Literal
        print("Feature enabled")
    case False:       # boolesches Literal
        print("Feature disabled")
    case None:        # None-Literal
        print("Feature not configured")
    case 0:           # Integer-Literal
        print("Feature explicitly turned off")
    case "auto":      # String-Literal
        print("Feature set to automatic mode")
    case _:
        print("Invalid configuration value")

Output:

Feature enabled

Literal Patterns funktionieren mit Integers, Floats, Strings, Booleans und None. Python prüft auf Gleichheit nach denselben Regeln wie der ==-Operator.

13.2.3) Multiple Patterns mit dem OR-Operator

Manchmal möchten Sie für mehrere verschiedene Werte denselben Code ausführen. Sie können mehrere Muster mit dem |-Operator (Pipe) kombinieren, der „oder“ bedeutet:

python
# Wochenend-Erkennung
day = "Saturday"
 
match day:
    case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
        print("It's a weekday - time to work!")
    case "Saturday" | "Sunday":
        print("It's the weekend - time to relax!")
    case _:
        print("Invalid day name")

Output:

It's the weekend - time to relax!

Der |-Operator erlaubt Ihnen, mehrere Muster anzugeben, die dieselbe Aktion auslösen sollen. Wenn das Subject auf eines der durch | getrennten Muster passt, wird dieser Case ausgeführt. Das ist deutlich sauberer, als separate Cases mit identischen Codeblöcken zu schreiben.

Sie können mit | verschiedene Musterarten mischen:

python
# Eingabevalidator für Ja/Nein-Fragen
response = "yes"
 
match response:
    case True | "yes":
        print("You confirmed the action")
    case False | "no":
        print("You cancelled the action")
    case _:
        print("Please answer yes or no")

Output:

You confirmed the action

13.2.4) Erfassen, welche Alternative passte, mit as

Wenn Sie mehrere Muster mit | verwenden, möchten Sie vielleicht wissen, welcher konkrete Wert gepasst hat. Dafür können Sie das Schlüsselwort as verwenden, um den gematchten Wert zu erfassen:

python
# Statuscode-Handler mit gruppierten Antworten
status = 201
 
match status:
    case 200 | 201 | 202 | 204 as success_code:
        print(f"Success: {success_code}")
    case 400 | 401 | 403 | 404 as client_error:
        print(f"Client error: {client_error}")
    case 500 | 502 | 503 as server_error:
        print(f"Server error: {server_error}")
    case _:
        print("Unknown status code")

Output:

Success: 201

Das Schlüsselwort as erzeugt eine Bindungsvariable, die erfasst, welche Alternative gematcht hat. In diesem Beispiel wird success_code an 201 gebunden, weil das der konkrete Wert ist, der aus den Alternativen 200 | 201 | 202 | 204 gepasst hat.

Hier ist ein weiteres Beispiel, das zeigt, wie das für Logging nützlich ist:

python
# Log-Level-Verarbeiter
log_level = "WARN"
 
match log_level:
    case "DEBUG" | "TRACE" as level:
        print(f"Verbose logging: {level}")
        print("Detailed diagnostic information will be recorded")
    case "INFO" | "NOTICE" as level:
        print(f"Informational: {level}")
        print("Normal operation messages will be recorded")
    case "WARN" | "WARNING" as level:
        print(f"Warning level: {level}")
        print("Potential issues detected")
    case "ERROR" | "FATAL" | "CRITICAL" as level:
        print(f"Error level: {level}")
        print("Immediate attention required")
    case _:
        print("Unknown log level")

Output:

Warning level: WARN
Potential issues detected

13.3) Werte extrahieren mit Bindungsvariablen

13.3.1) Was sind Bindungsvariablen?

Bisher haben wir gegen Literalwerte gematcht. Aber Pattern Matching wird wirklich mächtig, wenn Sie Teile der Daten, gegen die Sie matchen, erfassen oder extrahieren können. Eine Bindungsvariable (auch Capture Pattern genannt) ist ein Name in einem Muster, der den gematchten Wert erfasst und ihn im Case-Block verfügbar macht.

Hier ist ein einfaches Beispiel:

python
# Einfaches Erfassen eines Werts
command = "save"
 
match command:
    case "quit":
        print("Exiting program")
    case action:  # Das ist eine Bindungsvariable
        print(f"Executing action: {action}")

Output:

Executing action: save

Das Muster action ist eine Bindungsvariable. Es passt auf jeden Wert (wie das Wildcard _), aber anders als _ erfasst es diesen Wert und weist ihn dem Namen action zu. Im Case-Block können Sie action verwenden, um auf den gematchten Wert zu verweisen.

Wichtiger Unterschied: Eine Bindungsvariable passt auf alles, genau wie _. Der Unterschied ist, dass _ den Wert verwirft, während eine Bindungsvariable ihn für die Verwendung im Case-Block erfasst.

13.3.2) Binding Variables vs. Wildcards

Vergleichen wir Bindungsvariablen und Wildcards direkt:

python
# Verwendung des Wildcards - der Wert wird nicht erfasst
status = 403
 
match status:
    case 200:
        print("Success")
    case _:
        print("Some other status code")  # Zugriff auf den tatsächlichen Wert nicht möglich

Output:

Some other status code

Jetzt mit einer Bindungsvariable:

python
# Verwendung einer Bindungsvariable - der Wert wird erfasst
status = 403
 
match status:
    case 200:
        print("Success")
    case code:  # Bindungsvariable erfasst den Wert
        print(f"Status code {code} received")

Output:

Status code 403 received

Die Bindungsvariable code erfasst den Wert 403 und macht ihn im Case-Block verfügbar. Das ist nützlich, wenn Sie mit dem tatsächlichen Wert arbeiten müssen, der nicht auf Ihre spezifischen Muster gepasst hat.

13.3.3) Tuple Patterns matchen und Komponenten extrahieren

Pattern Matching wird besonders leistungsfähig mit strukturierten Daten wie Tuples. Sie können die Form eines Tuples matchen und seine Komponenten gleichzeitig extrahieren. Obwohl wir Tuples in Kapitel 15 im Detail behandeln, konzentriert sich dieses Beispiel nur darauf, wie Tuple Patterns in match-Anweisungen funktionieren.

python
# Koordinatensystem – ein Tuple-Muster matchen
point = (3, 7)
 
match point:
    case (0, 0):
        print("Origin point")
    case (0, y):  # Passt auf jeden Punkt auf der y-Achse
        print(f"On y-axis at y={y}")
    case (x, 0):  # Passt auf jeden Punkt auf der x-Achse
        print(f"On x-axis at x={x}")
    case (x, y):  # Passt auf jeden anderen Punkt
        print(f"Point at coordinates ({x}, {y})")

Output:

Point at coordinates (3, 7)

Schauen wir uns an, was passiert:

  1. Das Subject point ist das Tuple (3, 7)
  2. Python prüft jedes Case-Muster der Reihe nach
  3. Die ersten drei Muster passen nicht, weil sie den Wert 0 an einer bestimmten Position erfordern, und das Tuple (3, 7) hat kein Element, das gleich 0 ist
  4. Das Muster (x, y) passt, weil es ein Tuple mit zwei Elementen ist
  5. Python bindet x an 3 und y an 7
  6. Der Case-Block wird mit diesen erfassten Werten ausgeführt

Hier ist ein weiteres Beispiel, das verschiedene Tuple Patterns zeigt:

python
# RGB-Farbanalysator
color = (255, 0, 0)
 
match color:
    case (0, 0, 0):
        print("Black")
    case (255, 255, 255):
        print("White")
    case (r, 0, 0):  # Reines Rot mit variierender Intensität
        print(f"Pure red with intensity {r}")
    case (0, g, 0):  # Reines Grün
        print(f"Pure green with intensity {g}")
    case (0, 0, b):  # Reines Blau
        print(f"Pure blue with intensity {b}")
    case (r, g, b):  # Jede andere Farbe
        print(f"RGB color: red={r}, green={g}, blue={b}")

Output:

Pure red with intensity 255

Diese Eingabe passt auf das Muster (r, 0, 0), weil das Tuple drei Elemente hat, die letzten beiden 0 sind und der erste Wert an r gebunden wird.

13.3.4) List Patterns matchen

Sie können auch List Patterns matchen und Elemente extrahieren. Wir behandeln Listen in Kapitel 14 im Detail; fürs Erste konzentriert sich dieses Beispiel darauf, wie List Patterns in match-Anweisungen funktionieren:

python
# Befehl mit Argumenten
command = ["move", "north", "5"]
 
match command:
    case ["quit"]:
        print("Exiting game")
    case ["look"]:
        print("You look around the room")
    case ["move", direction]:
        print(f"Moving {direction}")
    case ["move", direction, distance]:
        print(f"Moving {direction} for {distance} steps")
    case _:
        print("Unknown command")

Output:

Moving north for 5 steps

Das Muster ["move", direction, distance] passt auf eine Liste mit drei Elementen, bei der das erste Element "move" ist. Es erfasst das zweite Element als direction und das dritte als distance.

Hier ist ein praktisches Beispiel mit variierenden Listenlängen:

python
# Verarbeiter für Warenkorb-Artikel
item = ["laptop", 999.99, 2]
 
match item:
    case [name]:  # Artikel nur mit Name
        print(f"Item: {name} (no price or quantity specified)")
    case [name, price]:  # Artikel mit Name und Preis
        print(f"Item: {name}, Price: ${price}, Quantity: 1 (default)")
    case [name, price, quantity]:  # Vollständige Artikeldaten
        total = price * quantity
        print(f"Item: {name}, Price: ${price}, Quantity: {quantity}")
        print(f"Subtotal: ${total}")
    case _:
        print("Invalid item format")

Output:

Item: laptop, Price: $999.99, Quantity: 2
Subtotal: $1999.98

Der Case [name, price, quantity] wird ausgeführt, weil die Liste genau drei Elemente hat und jedes Element an seine entsprechende Variable gebunden wird.

13.3.5) Dictionary Patterns matchen

Pattern Matching funktioniert auch mit Dictionaries und erlaubt Ihnen, bestimmte Keys zu matchen und ihre Werte zu extrahieren. Obwohl wir Dictionaries in Kapitel 16 im Detail behandeln, konzentriert sich dieser Abschnitt nur darauf, wie Dictionary Patterns in match-Anweisungen funktionieren.

python
# Verarbeiter für Benutzerprofile
user = {"name": "Alice", "role": "admin", "active": True}
 
match user:
    case {"role": "admin", "active": True}:
        print("Active administrator - full access granted")
    case {"role": "admin", "active": False}:
        print("Inactive administrator - access suspended")
    case {"role": role, "active": True}:  # Den Rollenwert erfassen
        print(f"Active user with role: {role}")
    case {"role": role, "active": False}:
        print(f"Inactive user with role: {role}")
    case _:
        print("Invalid user profile")

Output:

Active administrator - full access granted

Der Case {"role": "admin", "active": True} wird ausgeführt, weil Dictionary Patterns das Matchen von Key-Value-Paaren erfordern, und dieses exakte Match wird vor allgemeineren Mustern geprüft.

Dictionary Patterns sind flexibel—sie matchen, wenn die angegebenen Keys mit den angegebenen Werten existieren, auch wenn das Dictionary zusätzliche Keys enthält:

python
# Handler für API-Antworten
response = {"status": "success", "data": {"id": 123, "name": "Product"}, "timestamp": "2025-12-17"}
 
match response:
    case {"status": "error", "message": msg}:
        print(f"Error occurred: {msg}")
    case {"status": "success", "data": data}:
        print(f"Success! Data received: {data}")
    case _:
        print("Unknown response format")

Output:

Success! Data received: {'id': 123, 'name': 'Product'}

Das Muster {"status": "success", "data": data} passt, obwohl das Dictionary einen zusätzlichen Key "timestamp" enthält. Das Muster erfordert nur, dass die angegebenen Keys mit den angegebenen Werten (oder Mustern) existieren.

13.3.6) Literale und Bindungsvariablen kombinieren

Sie können Literal Patterns und Bindungsvariablen mischen, um anspruchsvolle Matching-Logik zu erstellen: Im Gegensatz zu den früheren Tuple-Beispielen, die sich auf das Matchen von Struktur und Position konzentrierten, zeigt dieses Beispiel, wie Literalwerte und Bindungsvariablen kombiniert werden können, um reale Entscheidungslogik umzusetzen.

python
# HTTP-Request-Router
request = ("GET", "/api/users", 42)
 
match request:
    case ("GET", "/", None):
        print("Homepage request")
    case ("GET", path, None):
        print(f"GET request for: {path}")
    case ("POST", path, data):
        print(f"POST request to {path} with data: {data}")
    case ("GET", path, user_id):
        print(f"GET request for {path} with user ID: {user_id}")
    case _:
        print("Unsupported request type")

Output:

GET request for /api/users with user ID: 42

Dieses Beispiel zeigt, wie Sie spezifische Werte (wie "GET") matchen können, während Sie andere (wie path und user_id) im selben Muster erfassen.

13.3.7) Praktisches Beispiel: Event Handler

Bauen wir ein vollständiges Beispiel, das die Stärke von Binding Variables demonstriert:

python
# Game-Event-Handler
event = ("player_move", {"x": 10, "y": 5, "speed": 2})
 
match event:
    case ("player_move", {"x": x, "y": y}):
        print(f"Player moved to position ({x}, {y})")
    case ("player_attack", {"target": target, "damage": damage}):
        print(f"Player attacked {target} for {damage} damage")
    case ("item_pickup", {"item": item_name}):
        print(f"Player picked up: {item_name}")
    case ("game_over", {"score": final_score}):
        print(f"Game ended. Final score: {final_score}")
    case (event_type, data):
        print(f"Unknown event type: {event_type}")
        print(f"Event data: {data}")

Output:

Player moved to position (10, 5)

Dieser Event Handler matcht Tuples, die einen Event-Typ und ein Dictionary mit Event-Daten enthalten. Er extrahiert spezifische Werte aus dem Dictionary abhängig vom Event-Typ, was es leicht macht, verschiedene Arten von Events mit sauberem, gut lesbarem Code zu verarbeiten.

13.4) Zusätzliche Bedingungen mit dem if Guard hinzufügen

13.4.1) Was sind Guards?

Manchmal müssen Sie ein Muster matchen und eine zusätzliche Bedingung prüfen. Ein if Guard ist eine zusätzliche Bedingung, die Sie einem Case-Muster mit dem Schlüsselwort if hinzufügen können. Der Case passt nur, wenn sowohl das Muster passt als auch die Guard-Bedingung wahr ist.

Hier ist die Syntax:

python
match subject:
    case pattern if condition:
        # Code wird nur ausgeführt, wenn pattern passt UND condition wahr ist

Sehen wir uns ein einfaches Beispiel an:

python
# Zugriffskontrolle nach Alter
age = 16
 
match age:
    case age if age >= 18:
        print("Adult - full access granted")
    case age if age >= 13:
        print("Teen - limited access granted")
    case age if age >= 0:
        print("Child - parental supervision required")
    case _:
        print("Invalid age")

Output:

Teen - limited access granted

In diesem Beispiel erfasst die Bindungsvariable age den Wert, und der Guard if age >= 13 fügt eine zusätzliche Bedingung hinzu. Der Case passt nur, wenn der Wert 13 oder größer ist. Da age 16 ist, passt der zweite Case und wird ausgeführt.

13.4.2) Wie Guards ausgewertet werden

Es ist wichtig, die Auswertungsreihenfolge zu verstehen. Hier ist eine detaillierte Visualisierung, die zeigt, wie Guards mit Pattern Matching zusammenspielen:

Nein

Ja

Ja

Nein

Ja

Nein

Case-Muster prüfen

Muster passt?

Nächsten Case versuchen

Guard-Bedingung auswerten

Guard ist True?

Case-Block ausführen

match-Anweisung beenden

Weitere Cases?

Kein Match gefunden – nach match fortfahren

Python prüft zuerst, ob das Muster passt. Nur wenn das Muster passt, wertet Python die Guard-Bedingung aus. Wenn der Guard false ist, geht Python zum nächsten Case—obwohl das Muster gepasst hat.

Hier ist ein Beispiel, das das demonstriert:

python
# Temperatur-Warnsystem
temperature = 25
 
match temperature:
    case temp if temp > 35:
        print(f"Extreme heat warning: {temp}°C")
    case temp if temp > 30:
        print(f"High temperature alert: {temp}°C")
    case temp if temp > 20:
        print(f"Comfortable temperature: {temp}°C")
    case temp if temp > 10:
        print(f"Cool temperature: {temp}°C")
    case temp:
        print(f"Cold temperature: {temp}°C")

Output:

Comfortable temperature: 25°C

Jeder Case verwendet die Bindungsvariable temp, um den Temperaturwert zu erfassen, und wendet dann einen Guard an, um zu prüfen, ob er in einen bestimmten Bereich fällt. Die Cases werden der Reihe nach geprüft, daher wird der erste passende Case mit einem wahren Guard ausgeführt.

13.4.3) Guards mit Literal Patterns

Sie können Guards mit Literal Patterns kombinieren, um spezifischeres Matching zu erstellen:

python
# Rabattrechner basierend auf Artikeltyp und Menge
item = ("book", 5)
 
match item:
    case ("book", quantity) if quantity >= 10:
        discount = 0.20  # 20% Rabatt für 10+ Bücher
        print(f"Bulk book order: {quantity} books, {discount*100}% discount")
    case ("book", quantity) if quantity >= 5:
        discount = 0.10  # 10% Rabatt für 5-9 Bücher
        print(f"Book order: {quantity} books, {discount*100}% discount")
    case ("book", quantity):
        discount = 0.0  # Kein Rabatt für weniger als 5 Bücher
        print(f"Book order: {quantity} books, no discount")
    case (item_type, quantity):
        print(f"Order: {quantity} {item_type}(s)")

Output:

Book order: 5 books, 10.0% discount

Das Muster ("book", quantity) passt auf ein Tuple, bei dem das erste Element "book" ist. Der Guard if quantity >= 5 fügt die Bedingung hinzu, dass die Menge mindestens 5 sein muss.

13.4.4) Guards mit komplexen Bedingungen

Guards können jeden booleschen Ausdruck verwenden, einschließlich komplexer Bedingungen mit and, or und not:

python
# Bewertung von Schülernoten unter Berücksichtigung der Anwesenheit
student = {"name": "Bob", "grade": 85, "attendance": 75}
 
match student:
    case {"grade": g, "attendance": a} if g >= 90 and a >= 90:
        status = "Excellent"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 80 and a >= 80:
        status = "Good"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 70 and a >= 70:
        status = "Satisfactory"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 60 or a >= 60:
        status = "Needs Improvement"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case _:
        print("Failing - immediate intervention required")

Output:

Grade: 85, Attendance: 75% - Status: Satisfactory

Der Guard if g >= 70 and a >= 70 erfordert, dass sowohl die Note als auch die Anwesenheit mindestens 70 sind. Da Bob eine Note von 85 und eine Anwesenheit von 75% hat, passt dieser Case.

13.4.5) Praktisches Beispiel: Benutzer-Authentifizierungssystem

Bauen wir ein vollständiges Beispiel, das Guards verwendet, um ein realistisches Authentifizierungssystem zu implementieren:

python
# Benutzer-Authentifizierung mit rollenbasiertem Zugriff
user = {"username": "alice", "role": "admin", "active": True, "login_attempts": 0}
 
match user:
    case {"active": False}:
        print("Account suspended - contact administrator")
    case {"login_attempts": attempts} if attempts >= 3:
        print("Account locked due to too many failed login attempts")
    case {"role": "admin", "active": True}:
        print("Admin access granted - full system privileges")
    case {"role": "moderator", "active": True}:
        print("Moderator access granted - content management privileges")
    case {"role": role, "active": True} if role in ["editor", "author"]:
        print(f"{role.capitalize()} access granted - content creation privileges")
    case {"role": "user", "active": True}:
        print("User access granted - basic privileges")
    case _:
        print("Access denied - invalid user profile")

Output:

Admin access granted - full system privileges

Dieses Beispiel zeigt, wie Guards komplexe Business-Logik umsetzen können. Das System prüft mehrere Bedingungen: Kontostatus, Login-Versuche und rollenbasierte Berechtigungen. Jeder Case behandelt ein bestimmtes Szenario, wodurch die Authentifizierungslogik klar und wartbar wird.

13.5) Auf einfache Sequenz- und Mapping-Formen matchen

13.5.1) Sequenzen variabler Länge matchen

Manchmal müssen Sie Sequenzen unterschiedlicher Länge matchen. Pythons Pattern Matching unterstützt dies mit dem *-Operator, der null oder mehr Elemente erfasst.

python
# Command-Parser mit variablen Argumenten
command = ["copy", "file1.txt", "file2.txt", "file3.txt", "backup/"]
 
match command:
    case ["help"]:
        print("Available commands: copy, move, delete")
    case ["copy", source, destination]:
        print(f"Copying {source} to {destination}")
    case ["copy", *sources, destination]:
        print(f"Copying {len(sources)} files to {destination}")
        print(f"Source files: {sources}")
    case ["delete", *files]:
        print(f"Deleting {len(files)} file(s): {files}")
    case _:
        print("Unknown command")

Output:

Copying 3 files to backup/
Source files: ['file1.txt', 'file2.txt', 'file3.txt']

Das Muster ["copy", *sources, destination] passt auf eine Liste, die mit "copy" beginnt, mit einem Ziel endet und dazwischen eine beliebige Anzahl von Quelldateien enthält. *sources erfasst alle mittleren Elemente als Liste.

Wichtig: Sie können pro Sequenzmuster nur ein *-Muster verwenden, und es erfasst Elemente als Liste:

python
# Logeintrags-Parser
log_entry = ["2025-12-17", "10:30:45", "ERROR", "Database", "connection", "timeout"]
 
match log_entry:
    case [date, time, "ERROR", *error_details]:
        print(f"Error on {date} at {time}")
        print(f"Error details: {' '.join(error_details)}")
    case [date, time, "WARNING", *warning_details]:
        print(f"Warning on {date} at {time}")
        print(f"Warning details: {' '.join(warning_details)}")
    case [date, time, level, *message]:
        print(f"{level} on {date} at {time}: {' '.join(message)}")

Output:

Error on 2025-12-17 at 10:30:45
Error details: Database connection timeout

13.5.2) Sequenzmuster mit Guards kombinieren

Sie können Guards mit Sequenzmustern verwenden, um zusätzliche Bedingungen hinzuzufügen:

python
# Notenlisten-Analysator
grades = [85, 92, 78, 95, 88]
 
match grades:
    case []:
        print("No grades recorded")
    case [grade] if grade >= 90:
        print(f"Single excellent grade: {grade}")
    case [grade] if grade < 60:
        print(f"Single failing grade: {grade}")
    case [*all_grades] if len(all_grades) >= 5 and sum(all_grades) / len(all_grades) >= 90:
        average = sum(all_grades) / len(all_grades)
        print(f"Excellent performance! Average: {average:.1f}")
    case [*all_grades] if len(all_grades) >= 5:
        average = sum(all_grades) / len(all_grades)
        print(f"Performance review: {len(all_grades)} grades, Average: {average:.1f}")
    case [*all_grades]:
        print(f"Insufficient data: only {len(all_grades)} grade(s)")

Output:

Performance review: 5 grades, Average: 87.6

Das Muster [*all_grades] erfasst alle Elemente in der Liste, und der Guard prüft sowohl die Länge als auch berechnet den Durchschnitt, um die passende Nachricht zu bestimmen.


Pattern Matching mit match und case bietet eine leistungsstarke, ausdrucksstarke Möglichkeit, komplexe Entscheidungsfindung in Python zu handhaben. Von einfachem Wert-Matching bis hin zu ausgefeilten strukturellen Mustern mit Guards ermöglicht Ihnen dieses Feature, saubereren, besser wartbaren Code zu schreiben, um mehrere Fälle zu behandeln und Daten aus komplexen Strukturen zu extrahieren.

Während Sie weiter Python lernen, werden Sie feststellen, dass Pattern Matching die bedingte Logik ergänzt, die Sie in Kapitel 8 gelernt haben, und eine elegante Alternative bietet, wenn Sie mit mehreren klar unterscheidbaren Fällen arbeiten, besonders mit strukturierten Daten. Der Schlüssel ist, für jede Situation das richtige Werkzeug zu wählen: Verwenden Sie if-elif-else für einfache Bedingungen und boolesche Logik, und greifen Sie zu match-case, wenn Sie einen Wert gegen mehrere Möglichkeiten prüfen oder mit strukturierten Daten arbeiten, die eine musterbasierte Extraktion benötigen.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai