Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 653 – Präzise Semantik für Pattern Matching

Autor:
Mark Shannon <mark at hotpy.org>
Status:
Entwurf
Typ:
Standards Track
Erstellt:
09. Feb. 2021
Post-History:
18. Feb. 2021

Inhaltsverzeichnis

Zusammenfassung

Dieser PEP schlägt eine Semantik für Pattern Matching vor, die das allgemeine Konzept von PEP 634 berücksichtigt, aber präziser, leichter nachvollziehbar und schneller sein sollte.

Das Objektmodell wird um zwei spezielle (dunder) Attribute, __match_container__ und __match_class__, zusätzlich zu dem __match_args__ Attribut aus PEP 634 erweitert, um Pattern Matching zu unterstützen. Beide dieser neuen Attribute müssen Integer sein und __match_args__ muss ein Tupel eindeutiger Strings sein.

Mit diesem PEP

  • Die Semantik des Pattern Matching wird klarer, sodass Muster leichter nachvollziehbar sind.
  • Es wird möglich sein, Pattern Matching effizienter zu implementieren.
  • Pattern Matching wird für komplexe Klassen nutzbarer, indem Klassen mehr Kontrolle darüber erhalten, welche Muster sie abgleichen.

Motivation

Pattern Matching in Python, wie in PEP 634 beschrieben, wird zu Python 3.10 hinzugefügt. Leider ist PEP 634 nicht so präzise bezüglich der Semantik, wie es sein könnte, und erlaubt Klassen nicht genügend Kontrolle darüber, wie sie Muster abgleichen.

Präzise Semantik

PEP 634 enthält explizit einen Abschnitt über undefiniertes Verhalten. Große Mengen undefinierten Verhaltens mögen in einer Sprache wie C akzeptabel sein, aber in Python sollte es auf ein Minimum beschränkt werden. Pattern Matching in Python kann präziser definiert werden, ohne an Ausdrucksstärke oder Leistung zu verlieren.

Verbesserte Kontrolle über Klassenabgleich

PEP 634 delegiert die Entscheidung, ob eine Klasse eine Sequenz oder ein Mapping ist, an collections.abc. Nicht alle Klassen, die als Sequenzen betrachtet werden könnten, sind als Unterklassen von collections.abc.Sequence registriert. Dieser PEP erlaubt ihnen, Sequenzmuster abzugleichen, ohne die vollständige collections.abc.Sequence Maschinerie.

PEP 634 bevorzugt einige eingebaute Klassen mit einer speziellen Form des Abgleichs, dem "Self"-Abgleich. Zum Beispiel gleicht das Muster list(x) eine Liste ab und weist die Liste x zu. Indem Klassen erlaubt wird zu wählen, welche Arten von Mustern sie abgleichen, können andere Klassen diese Form ebenfalls verwenden.

Zum Beispiel könnten wir mit sympy schreiben

# a*a == a**2
case Mul(args=[Symbol(a), Symbol(b)]) if a == b:
    return Pow(a, 2)

Was erfordert, dass die sympy-Klasse Symbol einen "Self"-Abgleich durchführt. Für sympy ist es möglich, dieses Muster mit PEP 634 zu unterstützen, aber ein wenig knifflig. Mit diesem PEP kann es sehr einfach implementiert werden [1].

Robustheit

Mit diesem PEP wird der Zugriff auf Attribute während des Pattern Matching gut definiert und deterministisch. Dies macht Pattern Matching fehlerresistenter beim Abgleichen von Objekten mit versteckten Nebeneffekten, wie z. B. Objekt-Relationalen Mappern. Objekte erhalten mehr Kontrolle über ihre eigene Dekonstruktion, was unbeabsichtigte Folgen verhindern kann, falls der Attributzugriff Nebeneffekte hat.

PEP 634 stützt sich auf das collections.abc Modul, wenn es bestimmt, welche Muster ein Wert abgleichen kann, und importiert es bei Bedarf implizit. Dieser PEP eliminiert überraschende Importfehler und irreführende Audit-Ereignisse durch diese Imports.

Effiziente Implementierung

Die in diesem PEP vorgeschlagene Semantik ermöglicht eine effiziente Implementierung, teilweise aufgrund einer präzisen Semantik und teilweise durch die Nutzung des Objektmodells.

Mit präziser Semantik ist es möglich, darüber nachzudenken, welche Code-Transformationen korrekt sind, und somit Optimierungen effektiv anzuwenden.

Da das Objektmodell ein Kernbestandteil von Python ist, verarbeiten Implementierungen spezielle Attribut-Lookups bereits effizient. Das Nachschlagen eines speziellen Attributs ist viel schneller als das Durchführen eines Unterklassen-Tests bei einer abstrakten Basisklasse.

Begründung

Das Objektmodell und spezielle Methoden sind das Herzstück der Python-Sprache. Folglich unterstützen Implementierungen sie gut. Die Verwendung von speziellen Attributen für Pattern Matching ermöglicht es, Pattern Matching so zu implementieren, dass es gut mit dem Rest der Implementierung integriert ist, und somit einfacher zu warten und wahrscheinlich performanter ist.

Eine `match`-Anweisung führt eine Reihe von Musterabgleichen durch. Im Allgemeinen hat das Abgleichen eines Musters drei Teile

  1. Kann der Wert diese Art von Muster abgleichen?
  2. Beim Dekonstruieren, gleicht der Wert dieses spezifische Muster ab?
  3. Ist die Bedingung wahr?

Um zu bestimmen, ob ein Wert eine bestimmte Art von Muster abgleichen kann, fügen wir die Attribute __match_container__ und __match_class__ hinzu. Dies ermöglicht es, die Art eines Wertes auf effiziente Weise zu bestimmen.

Spezifikation

Ergänzungen zum Objektmodell

Die Attribute __match_container__ und __match_class__ werden zu object hinzugefügt. __match_container__ sollte von Klassen überschrieben werden, die Mapping- oder Sequenzmuster abgleichen möchten. __match_class__ sollte von Klassen überschrieben werden, die das Standardverhalten beim Abgleichen von Klassenmustern ändern möchten.

__match_container__ muss ein Integer sein und sollte genau einer der folgenden sein

0
MATCH_SEQUENCE = 1
MATCH_MAPPING = 2

MATCH_SEQUENCE wird verwendet, um anzuzeigen, dass Instanzen der Klasse Sequenzmuster abgleichen können.

MATCH_MAPPING wird verwendet, um anzuzeigen, dass Instanzen der Klasse Mapping-Muster abgleichen können.

__match_class__ muss ein Integer sein und sollte genau einer der folgenden sein

0
MATCH_SELF = 8

MATCH_SELF wird verwendet, um anzuzeigen, dass bei einem Klassenmuster mit einem einzigen Positionsargument das Subjekt und nicht seine Dekonstruktion verwendet wird.

Hinweis

Im Rest dieses Dokuments werden wir uns auf die oben genannten Werte nur per Namen beziehen. Symbolische Konstanten werden sowohl für Python als auch für C bereitgestellt, und die Werte werden niemals geändert.

object wird die folgenden Werte für die speziellen Attribute haben

__match_container__ = 0
__match_class__= 0
__match_args__ = ()

Diese speziellen Attribute werden wie gewohnt vererbt.

Wenn __match_args__ überschrieben wird, muss es ein Tupel von eindeutigen Strings enthalten. Es kann leer sein.

Hinweis

__match_args__ wird automatisch für Dataclasses und Named Tuples generiert, wie in PEP 634 spezifiziert.

Die Pattern-Matching-Implementierung ist *nicht* verpflichtet zu prüfen, ob diese Attribute sich wie spezifiziert verhalten. Wenn der Wert von __match_container__, __match_class__ oder __match_args__ nicht wie spezifiziert ist, kann die Implementierung jede Ausnahme auslösen oder das falsche Muster abgleichen. Natürlich steht es Implementierungen frei, diese Eigenschaften zu prüfen und aussagekräftige Fehlermeldungen bereitzustellen, wenn sie dies effizient tun können.

Semantik des Matching-Prozesses

Im Folgenden sind alle unten aufgeführten zusätzlichen Codes, die nicht im Originalquelltext vorhanden sind, werden keine Zeilenereignisse auslösen, gemäß PEP 626.

Variablen der Form $var sind temporäre Variablen und für das Python-Programm nicht sichtbar. Sie können durch Introspektion sichtbar sein, aber das ist ein Implementierungsdetail und sollte nicht davon abhängig gemacht werden. Die Pseudo-Anweisung FAIL wird verwendet, um anzuzeigen, dass der Abgleich für dieses Muster fehlgeschlagen ist und dass der Abgleich zum nächsten Muster übergehen sollte. Wenn die Kontrolle das Ende der Übersetzung ohne Erreichen eines FAIL erreicht, hat es abgeglichen, und folgende Muster werden ignoriert.

Variablen der Form $ALL_CAPS sind Metavariablen, die ein syntaktisches Element enthalten, sie sind keine normalen Variablen. So ist $VARS = $items keine Zuweisung von $items an $VARS, sondern ein Entpacken von $items in die Variablen, die $VARS enthält. Zum Beispiel bei der abstrakten Syntax case [$VARS]: und der konkreten Syntax case[a, b]: würde $VARS die Variablen (a, b) enthalten, nicht die Werte dieser Variablen.

Die Pseudo-Funktion QUOTE nimmt eine Variable und gibt den Namen dieser Variablen zurück. Wenn zum Beispiel die Meta-Variable $VAR die Variable foo enthielte, dann wäre QUOTE($VAR) == "foo".

Präambel

Vor dem Abgleich irgendeines Musters wird der abzugleichende Ausdruck ausgewertet

match expr:

übersetzt sich in

$value = expr

Capture-Muster

Capture-Muster passen immer, also das unabweisbare Muster

case capture_var:

übersetzt sich in

capture_var = $value

Wildcard-Muster

Wildcard-Muster passen immer, also

case _:

übersetzt sich in

# No code -- Automatically matches

Literale Muster

Das Literal-Muster

case LITERAL:

übersetzt sich in

if $value != LITERAL:
    FAIL

außer wenn das Literal eines von None, True oder False ist, dann übersetzt es sich in

if $value is not LITERAL:
    FAIL

Wertmuster

Das Wert-Muster

case value.pattern:

übersetzt sich in

if $value != value.pattern:
    FAIL

Sequenzmuster

Ein Muster, das kein Stern-Muster enthält

case [$VARS]:

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_SEQUENCE:
    FAIL
if len($value) != len($VARS):
    FAIL
$VARS = $value

Beispiel: [2]

Ein Muster, das ein Stern-Muster enthält

case [$VARS]

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_SEQUENCE:
    FAIL
if len($value) < len($VARS):
    FAIL
$VARS = $value # Note that $VARS includes a star expression.

Beispiel: [3]

Abgleichmuster

Ein Muster, das kein Doppelstern-Muster enthält

case {$KEYWORD_PATTERNS}:

übersetzt sich in

$sentinel = object()
$kind = type($value).__match_container__
if $kind != MATCH_MAPPING:
    FAIL
# $KEYWORD_PATTERNS is a meta-variable mapping names to variables.
for $KEYWORD in $KEYWORD_PATTERNS:
    $tmp = $value.get(QUOTE($KEYWORD), $sentinel)
    if $tmp is $sentinel:
        FAIL
    $KEYWORD_PATTERNS[$KEYWORD] = $tmp

Beispiel: [4]

Ein Muster, das ein Doppelstern-Muster enthält

case {$KEYWORD_PATTERNS, **$DOUBLE_STARRED_PATTERN}:

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_MAPPING:
    FAIL
# $KEYWORD_PATTERNS is a meta-variable mapping names to variables.
$tmp = dict($value)
if not $tmp.keys() >= $KEYWORD_PATTERNS.keys():
    FAIL:
for $KEYWORD in $KEYWORD_PATTERNS:
    $KEYWORD_PATTERNS[$KEYWORD] = $tmp.pop(QUOTE($KEYWORD))
$DOUBLE_STARRED_PATTERN = $tmp

Beispiel: [5]

Klassenmuster

Klassenmuster ohne Argumente

case ClsName():

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL

Klassenmuster mit einem einzelnen Positionsargument

case ClsName($VAR):

übersetzt sich in

$kind = type($value).__match_class__
if $kind == MATCH_SELF:
    if not isinstance($value, ClsName):
        FAIL
    $VAR = $value
else:
    As other positional-only class pattern

Nur-Positions-Klassenmuster

case ClsName($VARS):

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL
$attrs = ClsName.__match_args__
if len($attr) < len($VARS):
    raise TypeError(...)
try:
    for i, $VAR in enumerate($VARS):
        $VAR = getattr($value, $attrs[i])
except AttributeError:
    FAIL

Beispiel: [6]

Klassenmuster mit allen Schlüsselwort-Mustern

case ClsName($KEYWORD_PATTERNS):

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL
try:
    for $KEYWORD in $KEYWORD_PATTERNS:
        $tmp = getattr($value, QUOTE($KEYWORD))
        $KEYWORD_PATTERNS[$KEYWORD] = $tmp
except AttributeError:
    FAIL

Beispiel: [7]

Klassenmuster mit Positions- und Schlüsselwort-Mustern

case ClsName($VARS, $KEYWORD_PATTERNS):

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL
$attrs = ClsName.__match_args__
if len($attr) < len($VARS):
    raise TypeError(...)
$pos_attrs = $attrs[:len($VARS)]
try:
    for i, $VAR in enumerate($VARS):
        $VAR = getattr($value, $attrs[i])
    for $KEYWORD in $KEYWORD_PATTERNS:
        $name = QUOTE($KEYWORD)
        if $name in pos_attrs:
            raise TypeError(...)
        $KEYWORD_PATTERNS[$KEYWORD] = getattr($value, $name)
except AttributeError:
    FAIL

Beispiel: [8]

Verschachtelte Muster

Die obige Spezifikation geht davon aus, dass Muster nicht verschachtelt sind. Für verschachtelte Muster werden die obigen Übersetzungen rekursiv angewendet, indem temporäre Capture-Muster eingeführt werden.

Zum Beispiel das Muster

case [int(), str()]:

übersetzt sich in

$kind = type($value).__match_class__
if $kind != MATCH_SEQUENCE:
    FAIL
if len($value) != 2:
    FAIL
$value_0, $value_1 = $value
#Now match on temporary values
if not isinstance($value_0, int):
    FAIL
if not isinstance($value_1, str):
    FAIL

Guards

Bedingungen (Guards) werden zu einem Test übersetzt, der dem Rest der Übersetzung folgt

case pattern if guard:

übersetzt sich in

[translation for pattern]
if not guard:
    FAIL

Nicht konforme spezielle Attribute

Alle Klassen sollten sicherstellen, dass die Werte von __match_container__, __match_class__ und __match_args__ der Spezifikation entsprechen. Daher können Implementierungen ohne Überprüfung davon ausgehen, dass die folgenden Aussagen wahr sind

__match_container__ == 0 or __match_container__ == MATCH_SEQUENCE or __match_container__ == MATCH_MAPPING
__match_class__ == 0 or __match_class__ == MATCH_SELF

und dass __match_args__ ein Tupel eindeutiger Strings ist.

Werte der speziellen Attribute für Klassen in der Standardbibliothek

Für die Kern-Container-Klassen __match_container__ wird sein

  • list: MATCH_SEQUENCE
  • tuple: MATCH_SEQUENCE
  • dict: MATCH_MAPPING
  • bytearray: 0
  • bytes: 0
  • str: 0

Named Tuples erhalten __match_container__ auf MATCH_SEQUENCE gesetzt.

  • Alle anderen Klassen der Standardbibliothek, für die issubclass(cls, collections.abc.Mapping) wahr ist, erhalten __match_container__ auf MATCH_MAPPING gesetzt.
  • Alle anderen Klassen der Standardbibliothek, für die issubclass(cls, collections.abc.Sequence) wahr ist, erhalten __match_container__ auf MATCH_SEQUENCE gesetzt.

Für die folgenden eingebauten Klassen wird __match_class__ auf MATCH_SELF gesetzt

  • bool
  • bytearray
  • bytes
  • float
  • frozenset
  • int
  • set
  • str
  • list
  • tuple
  • dict

Sicherheitsimplikationen

Keine.

Implementierung

Die naive Implementierung, die sich aus der Spezifikation ergibt, wird nicht sehr effizient sein. Glücklicherweise gibt es einige einigermaßen einfache Transformationen, die zur Leistungssteigerung verwendet werden können. Die Leistung sollte mit der Implementierung von PEP 634 (zum Zeitpunkt der Abfassung) mit der Veröffentlichung von 3.10 vergleichbar sein. Weitere Leistungsverbesserungen müssen möglicherweise auf die Veröffentlichung 3.11 warten.

Mögliche Optimierungen

Das Folgende ist nicht Teil der Spezifikation, sondern Leitlinien, um Entwicklern zu helfen, eine effiziente Implementierung zu erstellen.

Aufteilung der Auswertung in Bahnen

Da der erste Schritt beim Abgleichen jedes Musters eine Prüfung auf die Art ist, ist es möglich, alle Prüfungen auf die Art zu einer einzigen Mehrwegverzweigung am Anfang des Abgleichs zu kombinieren. Die Liste der Fälle kann dann in mehrere "Bahnen" dupliziert werden, die jeweils einer Art entsprechen. Es ist dann trivial, nicht abgleichbare Fälle aus jeder Bahn zu entfernen. Abhängig von der Art sind für jede Bahn unterschiedliche Optimierungsstrategien möglich. Beachten Sie, dass der Körper der Match-Klausel nicht dupliziert werden muss, sondern nur das Muster.

Sequenzmuster

Dies ist wahrscheinlich am komplexesten zu optimieren und am profitabelsten in Bezug auf die Leistung. Da jedes Muster nur einen Bereich von Längen abgleichen kann, oft nur eine einzelne Länge, kann die Testsequenz in eine explizite Iteration über die Sequenz umgeschrieben werden, wobei nur die Muster abgeglichen werden, die für diese Sequenzlänge gelten.

Zum Beispiel:

case []:
    A
case [x]:
    B
case [x, y]:
    C
case other:
    D

Kann grob übersetzt werden als

  # Choose lane
  $i = iter($value)
  for $0 in $i:
      break
  else:
      A
      goto done
  for $1 in $i:
      break
  else:
      x = $0
      B
      goto done
  for $2 in $i:
      del $0, $1, $2
      break
  else:
      x = $0
      y = $1
      C
      goto done
  other = $value
  D
done:

Mapping-Muster

Die beste Strategie hier ist wahrscheinlich die Bildung eines Entscheidungsbaums, der auf der Größe des Mappings und den vorhandenen Schlüsseln basiert. Es hat keinen Sinn, wiederholt auf die Anwesenheit eines Schlüssels zu prüfen. Zum Beispiel

match obj:
    case {a:x, b:y}:
        W
    case {a:x, c:y}:
        X
    case {a:x, b:_, c:y}:
        Y
    case other:
        Z

Wenn der Schlüssel "a" bei der Prüfung für Fall X nicht vorhanden ist, muss er nicht erneut für Y geprüft werden.

Die Mapping-Bahn kann ungefähr so implementiert werden

# Choose lane
if len($value) == 2:
    if "a" in $value:
        if "b" in $value:
            x = $value["a"]
            y = $value["b"]
            goto W
        if "c" in $value:
            x = $value["a"]
            y = $value["c"]
            goto X
elif len($value) == 3:
    if "a" in $value and "b" in $value:
        x = $value["a"]
        y = $value["c"]
        goto Y
other = $value
goto Z

Zusammenfassung der Unterschiede zwischen diesem PEP und PEP 634

Die Änderungen an der Semantik können zusammengefasst werden als

  • Erfordert, dass __match_args__ ein *Tupel* von Strings ist, nicht nur eine Sequenz. Dies macht Pattern Matching etwas robuster und optimierbarer, da angenommen werden kann, dass __match_args__ unveränderlich ist.
  • Die Auswahl der Art von Container-Mustern, die abgeglichen werden können, verwendet cls.__match_container__ anstelle von issubclass(cls, collections.abc.Mapping) und issubclass(cls, collections.abc.Sequence).
  • Ermöglicht es Klassen, sich bei Bedarf vollständig von der Dekonstruktion abzumelden, indem __match_class__ = 0 gesetzt wird.
  • Das Verhalten beim Abgleichen von Mustern ist präziser definiert, aber ansonsten unverändert.

Es gibt keine Änderungen an der Syntax. Alle Beispiele aus dem Tutorial von PEP 636 sollten weiterhin wie bisher funktionieren.

Abgelehnte Ideen

Verwendung von Attributen aus dem Instanzwörterbuch

Eine frühere Version dieses PEP verwendete nur Attribute aus dem Instanzwörterbuch beim Abgleichen eines Klassenmusters, wenn __match_class__ der Standardwert war. Die Absicht war, gebundene Methoden und andere synthetische Attribute nicht zu erfassen. Dies bedeutete jedoch auch, dass Eigenschaften ignoriert wurden.

Für die Klasse

class C:
    def __init__(self):
        self.a = "a"
    @property
    def p(self):
        ...
    def m(self):
        ...

Idealerweise würden wir die Attribute "a" und "p" abgleichen, aber nicht "m". Es gibt jedoch keine allgemeine Möglichkeit, dies zu tun, daher folgt dieser PEP jetzt der Semantik von PEP 634.

Lookup von __match_args__ auf dem Subjekt, nicht auf dem Muster

Eine frühere Version dieses PEP suchte nach __match_args__ in der Klasse des Subjekts und nicht in der im Muster angegebenen Klasse. Dies wurde aus mehreren Gründen abgelehnt

* Using the class specified in the pattern is more amenable to optimization and can offer better performance.
* Using the class specified in the pattern has the potential to provide better error reporting is some cases.
* Neither approach is perfect, both have odd corner cases. Keeping the status quo minimizes disruption.

Kombination von __match_class__ und __match_container__ zu einem einzigen Wert

Eine frühere Version dieses PEP kombinierte __match_class__ und __match_container__ zu einem einzigen Wert, __match_kind__. Die Verwendung eines einzigen Wertes hat einen kleinen Vorteil hinsichtlich der Leistung, führt aber wahrscheinlich zu unbeabsichtigten Änderungen beim Abgleich von Containern, wenn das Verhalten von Klassenmustern überschrieben wird, und umgekehrt.

Zurückgestellte Ideen

Die ursprüngliche Version dieses PEP enthielt den Match-Typ MATCH_POSITIONAL und die spezielle Methode __deconstruct__, die Klassen die volle Kontrolle über ihren Abgleich ermöglichen würde. Dies ist wichtig für Bibliotheken wie sympy.

Zum Beispiel könnten wir mit sympy schreiben

# sin(x)**2 + cos(x)**2 == 1
case Add(Pow(sin(a), 2), Pow(cos(b), 2)) if a == b:
    return 1

Für sympy ist es mit dem aktuellen Pattern Matching zwar möglich, Positionsmuster zu unterstützen, aber knifflig. Mit diesen zusätzlichen Funktionen kann es einfach implementiert werden [9].

Diese Idee wird in einem zukünftigen PEP für 3.11 enthalten sein. Es ist jedoch zu spät im Entwicklungszyklus von 3.10 für eine solche Änderung.

Einen separaten Wert haben, um alle Klassenübereinstimmungen abzulehnen

In einer früheren Version dieses PEP gab es einen separaten Wert für __match_class__, der es Klassen erlaubte, keine Klassenmuster abzugleichen, die eine Dekonstruktion erfordert hätten. Dies wäre jedoch redundant geworden, sobald MATCH_POSITIONAL eingeführt wurde, und verkompliziert die Spezifikation für einen extrem seltenen Fall.

Codebeispiele

class Symbol:
    __match_class__ = MATCH_SELF

Dieses

case [a, b] if a is b:

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_SEQUENCE:
    FAIL
if len($value) != 2:
    FAIL
a, b = $value
if not a is b:
    FAIL

Dieses

case [a, *b, c]:

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_SEQUENCE:
    FAIL
if len($value) < 2:
    FAIL
a, *b, c = $value

Dieses

case {"x": x, "y": y} if x > 2:

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_MAPPING:
    FAIL
$tmp = $value.get("x", $sentinel)
if $tmp is $sentinel:
    FAIL
x = $tmp
$tmp = $value.get("y", $sentinel)
if $tmp is $sentinel:
    FAIL
y = $tmp
if not x > 2:
    FAIL

Dieses

case {"x": x, "y": y, **z}:

übersetzt sich in

$kind = type($value).__match_container__
if $kind != MATCH_MAPPING:
    FAIL
$tmp = dict($value)
if not $tmp.keys() >= {"x", "y"}:
    FAIL
x = $tmp.pop("x")
y = $tmp.pop("y")
z = $tmp

Dieses

match ClsName(x, y):

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL
$attrs = ClsName.__match_args__
if len($attr) < 2:
    FAIL
try:
    x = getattr($value, $attrs[0])
    y = getattr($value, $attrs[1])
except AttributeError:
    FAIL

Dieses

match ClsName(a=x, b=y):

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL
try:
    x = $value.a
    y = $value.b
except AttributeError:
    FAIL

Dieses

match ClsName(x, a=y):

übersetzt sich in

if not isinstance($value, ClsName):
    FAIL
$attrs = ClsName.__match_args__
if len($attr) < 1:
    raise TypeError(...)
$positional_names = $attrs[:1]
try:
    x = getattr($value, $attrs[0])
    if "a" in $positional_names:
        raise TypeError(...)
    y = $value.a
except AttributeError:
    FAIL
class Basic:
    __match_class__ = MATCH_POSITIONAL
    def __deconstruct__(self):
        return self._args

Quelle: https://github.com/python/peps/blob/main/peps/pep-0653.rst

Zuletzt geändert: 2025-02-01 08:55:40 GMT