8. Zusammengesetzte Anweisungen¶
Zusammengesetzte Anweisungen enthalten (Gruppen von) anderen Anweisungen; sie beeinflussen oder steuern die Ausführung dieser anderen Anweisungen in irgendeiner Weise. Im Allgemeinen erstrecken sich zusammengesetzte Anweisungen über mehrere Zeilen, obwohl in einfachen Ausprägungen eine ganze zusammengesetzte Anweisung in einer Zeile enthalten sein kann.
Die if-, while- und for-Anweisungen implementieren traditionelle Kontrollflusskonstrukte. try gibt Ausnahmebehandlungsroutinen und/oder Bereinigungscode für eine Gruppe von Anweisungen an, während die with-Anweisung die Ausführung von Initialisierungs- und Finalisierungscode um einen Codeblock herum ermöglicht. Funktions- und Klassendefinitionen sind ebenfalls syntaktisch zusammengesetzte Anweisungen.
Eine zusammengesetzte Anweisung besteht aus einer oder mehreren „Klauseln“. Eine Klausel besteht aus einem Header und einer „Suite“. Die Klausel-Header einer bestimmten zusammengesetzten Anweisung befinden sich alle auf der gleichen Einrückungsebene. Jeder Klausel-Header beginnt mit einem eindeutig identifizierenden Schlüsselwort und endet mit einem Doppelpunkt. Eine Suite ist eine Gruppe von Anweisungen, die von einer Klausel gesteuert werden. Eine Suite kann eine oder mehrere durch Semikolon getrennte einfache Anweisungen auf derselben Zeile wie der Header sein, die auf den Doppelpunkt des Headers folgen, oder sie kann eine oder mehrere eingerückte Anweisungen auf nachfolgenden Zeilen sein. Nur die letztere Form einer Suite kann verschachtelte zusammengesetzte Anweisungen enthalten; das Folgende ist illegal, hauptsächlich weil nicht klar wäre, zu welcher if-Klausel eine nachfolgende else-Klausel gehören würde.
if test1: if test2: print(x)
Beachten Sie auch, dass das Semikolon in diesem Kontext stärker bindet als der Doppelpunkt, sodass im folgenden Beispiel entweder alle oder keine der print()-Aufrufe ausgeführt werden.
if x < y < z: print(x); print(y); print(z)
Zusammenfassend
compound_stmt:if_stmt|while_stmt|for_stmt|try_stmt|with_stmt|match_stmt|funcdef|classdef|async_with_stmt|async_for_stmt|async_funcdefsuite:stmt_listNEWLINE | NEWLINE INDENTstatement+ DEDENT statement:stmt_listNEWLINE |compound_stmtstmt_list:simple_stmt(";"simple_stmt)* [";"]
Beachten Sie, dass Anweisungen immer mit einem NEWLINE enden, möglicherweise gefolgt von einem DEDENT. Beachten Sie auch, dass optionale Fortsetzungsklauseln immer mit einem Schlüsselwort beginnen, das keine Anweisung beginnen kann, sodass keine Mehrdeutigkeiten bestehen (das Problem mit der „hängenden else“ wird in Python gelöst, indem verschachtelte if-Anweisungen eingerückt werden müssen).
Die Formatierung der Grammatikregeln in den folgenden Abschnitten platziert jede Klausel zur Klarheit auf einer separaten Zeile.
8.1. Die if-Anweisung¶
Die if-Anweisung wird für die bedingte Ausführung verwendet.
if_stmt: "if"assignment_expression":"suite("elif"assignment_expression":"suite)* ["else" ":"suite]
Sie wählt genau eine der Suiten aus, indem sie die Ausdrücke nacheinander auswertet, bis einer als wahr befunden wird (siehe Abschnitt Boolesche Operationen für die Definition von wahr und falsch); dann wird diese Suite ausgeführt (und kein anderer Teil der if-Anweisung wird ausgeführt oder ausgewertet). Wenn alle Ausdrücke falsch sind, wird die Suite der else-Klausel, falls vorhanden, ausgeführt.
8.2. Die while-Anweisung¶
Die while-Anweisung wird für wiederholte Ausführung verwendet, solange ein Ausdruck wahr ist.
while_stmt: "while"assignment_expression":"suite["else" ":"suite]
Dies testet den Ausdruck wiederholt und, wenn er wahr ist, führt die erste Suite aus; wenn der Ausdruck falsch ist (was das erste Mal sein kann, dass er getestet wird), wird die Suite der else-Klausel, falls vorhanden, ausgeführt und die Schleife beendet.
Eine in der ersten Suite ausgeführte break-Anweisung beendet die Schleife, ohne die Suite der else-Klausel auszuführen. Eine in der ersten Suite ausgeführte continue-Anweisung überspringt den Rest der Suite und kehrt zum Testen des Ausdrucks zurück.
8.3. Die for-Anweisung¶
Die for-Anweisung wird verwendet, um über die Elemente einer Sequenz (wie eine Zeichenkette, ein Tupel oder eine Liste) oder ein anderes iterierbares Objekt zu iterieren.
for_stmt: "for"target_list"in"starred_expression_list":"suite["else" ":"suite]
Der Ausdruck starred_expression_list wird einmal ausgewertet; er sollte ein iterierbares Objekt liefern. Für dieses iterierbare Objekt wird ein Iterator erstellt. Das erste vom Iterator bereitgestellte Element wird dann mithilfe der Standardregeln für Zuweisungen (siehe Abschnitt Zuweisungsanweisungen) der Zielvariable zugewiesen, und die Suite wird ausgeführt. Dies wiederholt sich für jedes vom Iterator bereitgestellte Element. Wenn der Iterator erschöpft ist, wird die Suite in der else-Klausel, falls vorhanden, ausgeführt und die Schleife beendet.
Eine in der ersten Suite ausgeführte break-Anweisung beendet die Schleife, ohne die Suite der else-Klausel auszuführen. Eine in der ersten Suite ausgeführte continue-Anweisung überspringt den Rest der Suite und fährt mit dem nächsten Element fort oder mit der else-Klausel, wenn kein nächstes Element vorhanden ist.
Die for-Schleife weist den Variablen in der Zielliste Werte zu. Dies überschreibt alle vorherigen Zuweisungen an diese Variablen, einschließlich derjenigen, die in der Suite der for-Schleife vorgenommen wurden.
for i in range(10):
print(i)
i = 5 # this will not affect the for-loop
# because i will be overwritten with the next
# index in the range
Namen in der Zielliste werden nicht gelöscht, wenn die Schleife beendet ist. Wenn die Sequenz jedoch leer ist, wurden sie überhaupt nicht von der Schleife zugewiesen. Tipp: Der eingebaute Typ range() stellt unveränderliche arithmetische Sequenzen von ganzen Zahlen dar. Zum Beispiel liefert die Iteration über range(3) nacheinander 0, dann 1 und dann 2.
Geändert in Version 3.11: Sternchenelemente sind jetzt in der Auswahlliste zulässig.
8.4. Die try-Anweisung¶
Die try-Anweisung gibt Ausnahmebehandlungsroutinen und/oder Bereinigungscode für eine Gruppe von Anweisungen an.
try_stmt:try1_stmt|try2_stmt|try3_stmttry1_stmt: "try" ":"suite("except" [expression["as"identifier]] ":"suite)+ ["else" ":"suite] ["finally" ":"suite] try2_stmt: "try" ":"suite("except" "*"expression["as"identifier] ":"suite)+ ["else" ":"suite] ["finally" ":"suite] try3_stmt: "try" ":"suite"finally" ":"suite
Zusätzliche Informationen zu Ausnahmen finden Sie in Abschnitt Ausnahmen, und Informationen zur Verwendung der raise-Anweisung zum Auslösen von Ausnahmen finden Sie in Abschnitt Die raise-Anweisung.
Geändert in Version 3.14: Unterstützung für das optionale Weglassen von Gruppierungsklammern bei Verwendung mehrerer Ausnahmetypen. Siehe PEP 758.
8.4.1. except-Klausel¶
Die except-Klausel(n) geben eine oder mehrere Ausnahmebehandlungsroutinen an. Wenn im try-Block keine Ausnahme auftritt, wird keine Ausnahmebehandlungsroutine ausgeführt. Wenn im try-Block eine Ausnahme auftritt, wird mit der Suche nach einer Ausnahmebehandlungsroutine begonnen. Diese Suche inspiziert die except-Klauseln der Reihe nach, bis eine gefunden wird, die mit der Ausnahme übereinstimmt. Eine except-Klausel ohne Ausdruck, falls vorhanden, muss die letzte sein; sie passt zu jeder Ausnahme.
Für eine except-Klausel mit einem Ausdruck muss der Ausdruck zu einem Ausnahmetyp oder einem Tupel von Ausnahmetypen ausgewertet werden. Klammern können weggelassen werden, wenn mehrere Ausnahmetypen angegeben sind und die as-Klausel nicht verwendet wird. Die ausgelöste Ausnahme passt zu einer except-Klausel, deren Ausdruck zur Klasse oder einer nicht-virtuellen Basisklasse des Ausnahmeobjekts ausgewertet wird oder zu einem Tupel, das eine solche Klasse enthält.
Wenn keine except-Klausel mit der Ausnahme übereinstimmt, wird die Suche nach einer Ausnahmebehandlungsroutine im umgebenden Code und auf dem Aufrufstapel fortgesetzt. [1]
Wenn die Auswertung eines Ausdrucks im Header einer except-Klausel eine Ausnahme auslöst, wird die ursprüngliche Suche nach einer Behandlungsroutine abgebrochen und eine Suche nach der neuen Ausnahme im umgebenden Code und auf dem Aufrufstapel begonnen (sie wird so behandelt, als ob die gesamte try-Anweisung die Ausnahme ausgelöst hätte).
Wenn eine passende except-Klausel gefunden wird, wird die Ausnahme der nach dem Schlüsselwort as in dieser except-Klausel angegebenen Zielvariable zugewiesen, falls vorhanden, und die Suite der except-Klausel wird ausgeführt. Alle except-Klauseln müssen einen ausführbaren Block haben. Wenn das Ende dieses Blocks erreicht ist, wird die Ausführung normal nach der gesamten try-Anweisung fortgesetzt. (Das bedeutet, dass, wenn zwei verschachtelte Behandlungsroutinen für dieselbe Ausnahme existieren und die Ausnahme im try-Block der inneren Behandlungsroutine auftritt, die äußere Behandlungsroutine die Ausnahme nicht behandelt.)
Wenn eine Ausnahme mithilfe von as target zugewiesen wurde, wird sie am Ende der except-Klausel gelöscht. Dies entspricht
except E as N:
foo
wurde übersetzt zu
except E as N:
try:
foo
finally:
del N
Dies bedeutet, dass die Ausnahme einer anderen Variablen zugewiesen werden muss, um sie nach der except-Klausel referenzieren zu können. Ausnahmen werden gelöscht, da sie mit dem an sie angehängten Traceback einen Referenzzyklus mit dem Stack-Frame bilden, wodurch alle lokalen Variablen in diesem Frame bis zur nächsten Garbage Collection am Leben gehalten werden.
Bevor die Suite einer except-Klausel ausgeführt wird, wird die Ausnahme im sys-Modul gespeichert, wo sie aus dem Inneren des Körpers der except-Klausel durch Aufruf von sys.exception() aufgerufen werden kann. Wenn eine Ausnahmebehandlungsroutine verlassen wird, wird die im sys-Modul gespeicherte Ausnahme auf ihren vorherigen Wert zurückgesetzt.
>>> print(sys.exception())
None
>>> try:
... raise TypeError
... except:
... print(repr(sys.exception()))
... try:
... raise ValueError
... except:
... print(repr(sys.exception()))
... print(repr(sys.exception()))
...
TypeError()
ValueError()
TypeError()
>>> print(sys.exception())
None
8.4.2. except*-Klausel¶
Die except*-Klausel(n) geben eine oder mehrere Behandlungsroutinen für Ausnahmegruppen (BaseExceptionGroup-Instanzen) an. Eine try-Anweisung kann entweder except- oder except*-Klauseln haben, aber nicht beides. Der Ausnahmetyp für die Übereinstimmung ist im Fall von except* obligatorisch, daher ist except*: ein Syntaxfehler. Der Typ wird wie im Fall von except interpretiert, aber die Übereinstimmung erfolgt mit den Ausnahmen, die in der Gruppe enthalten sind, die behandelt wird. Ein TypeError wird ausgelöst, wenn ein passender Typ eine Unterklasse von BaseExceptionGroup ist, da dies eine mehrdeutige Semantik hätte.
Wenn eine Ausnahme in der try-Block ausgelöst wird, wird jede except*-Klausel (siehe split()) in die Untergruppen der passenden und nicht passenden Ausnahmen aufgeteilt. Wenn die passende Untergruppe nicht leer ist, wird sie zur behandelten Ausnahme (dem von sys.exception() zurückgegebenen Wert) und der Zielvariable der except*-Klausel zugewiesen (falls vorhanden). Dann wird der Körper der except*-Klausel ausgeführt. Wenn die nicht passende Untergruppe nicht leer ist, wird sie auf die gleiche Weise von der nächsten except* verarbeitet. Dies wird fortgesetzt, bis alle Ausnahmen in der Gruppe übereingestimmt haben oder die letzte except*-Klausel ausgeführt wurde.
Nachdem alle except*-Klauseln ausgeführt wurden, wird die Gruppe der unbehandelten Ausnahmen mit allen Ausnahmen zusammengeführt, die aus except*-Klauseln ausgelöst oder neu ausgelöst wurden. Diese zusammengeführte Ausnahme-Gruppe wird weiter propagiert.
>>> try:
... raise ExceptionGroup("eg",
... [ValueError(1), TypeError(2), OSError(3), OSError(4)])
... except* TypeError as e:
... print(f'caught {type(e)} with nested {e.exceptions}')
... except* OSError as e:
... print(f'caught {type(e)} with nested {e.exceptions}')
...
caught <class 'ExceptionGroup'> with nested (TypeError(2),)
caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
+ Exception Group Traceback (most recent call last):
| File "<doctest default[0]>", line 2, in <module>
| raise ExceptionGroup("eg",
| [ValueError(1), TypeError(2), OSError(3), OSError(4)])
| ExceptionGroup: eg (1 sub-exception)
+-+---------------- 1 ----------------
| ValueError: 1
+------------------------------------
Wenn die vom try-Block ausgelöste Ausnahme keine Ausnahme-Gruppe ist und ihr Typ mit einer der except*-Klauseln übereinstimmt, wird sie abgefangen und von einer Ausnahme-Gruppe mit einer leeren Meldungszeichenkette umschlossen. Dies stellt sicher, dass der Typ des Zielvariablen e konsistent BaseExceptionGroup ist.
>>> try:
... raise BlockingIOError
... except* BlockingIOError as e:
... print(repr(e))
...
ExceptionGroup('', (BlockingIOError()))
break, continue und return dürfen nicht in einer except*-Klausel vorkommen.
8.4.3. else-Klausel¶
Die optionale else-Klausel wird ausgeführt, wenn die Steuerung die try-Suite verlässt, keine Ausnahme ausgelöst wurde und keine return-, continue- oder break-Anweisung ausgeführt wurde. Ausnahmen in der else-Klausel werden nicht von den vorhergehenden except-Klauseln behandelt.
8.4.4. finally-Klausel¶
Wenn finally vorhanden ist, gibt es eine „Bereinigungs“-Behandlungsroutine an. Die try-Klausel wird ausgeführt, einschließlich aller except- und else-Klauseln. Wenn in einer der Klauseln eine Ausnahme auftritt und nicht behandelt wird, wird die Ausnahme vorübergehend gespeichert. Die finally-Klausel wird ausgeführt. Wenn eine gespeicherte Ausnahme vorliegt, wird sie am Ende der finally-Klausel erneut ausgelöst. Wenn die finally-Klausel eine andere Ausnahme auslöst, wird die gespeicherte Ausnahme als Kontext der neuen Ausnahme gesetzt. Wenn die finally-Klausel eine return-, break- oder continue-Anweisung ausführt, wird die gespeicherte Ausnahme verworfen. Diese Funktion gibt zum Beispiel 42 zurück.
def f():
try:
1/0
finally:
return 42
Die Ausnahmeinformationen sind während der Ausführung der finally-Klausel für das Programm nicht verfügbar.
Wenn eine return-, break- oder continue-Anweisung in der try-Suite einer try…finally-Anweisung ausgeführt wird, wird die finally-Klausel ebenfalls „auf dem Weg hinaus“ ausgeführt.
Der Rückgabewert einer Funktion wird durch die letzte ausgeführte return-Anweisung bestimmt. Da die finally-Klausel immer ausgeführt wird, ist eine in der finally-Klausel ausgeführte return-Anweisung immer die letzte ausgeführte. Die folgende Funktion gibt „finally“ zurück.
def foo():
try:
return 'try'
finally:
return 'finally'
Geändert in Version 3.8: Vor Python 3.8 war eine continue-Anweisung in der finally-Klausel aufgrund eines Implementierungsproblems illegal.
Geändert in Version 3.14: Der Compiler gibt eine SyntaxWarning aus, wenn eine return-, break- oder continue-Anweisung in einem finally-Block vorkommt (siehe PEP 765).
8.5. Die with-Anweisung¶
Die with-Anweisung wird verwendet, um die Ausführung eines Blocks mit den von einem Kontextmanager definierten Methoden zu umschließen (siehe Abschnitt With Statement Context Managers). Dies ermöglicht es, gängige try…except…finally-Nutzungsmuster für eine bequeme Wiederverwendung zu kapseln.
with_stmt: "with" ( "("with_stmt_contents","? ")" |with_stmt_contents) ":"suitewith_stmt_contents:with_item(","with_item)* with_item:expression["as"target]
Die Ausführung der with-Anweisung mit einem „Element“ verläuft wie folgt:
Der Kontextausdruck (der Ausdruck im
with_item) wird ausgewertet, um einen Kontextmanager zu erhalten.Die
__enter__()-Methode des Kontextmanagers wird für die spätere Verwendung geladen.Die
__exit__()-Methode des Kontextmanagers wird für die spätere Verwendung geladen.Die
__enter__()-Methode des Kontextmanagers wird aufgerufen.Wenn eine Zielvariable in der
with-Anweisung enthalten war, wird der Rückgabewert von__enter__()ihm zugewiesen.Hinweis
Die
with-Anweisung garantiert, dass, wenn die__enter__()-Methode ohne Fehler zurückkehrt,__exit__()immer aufgerufen wird. Wenn also ein Fehler während der Zuweisung an die Zielliste auftritt, wird er genauso behandelt wie ein Fehler, der innerhalb der Suite auftritt. Siehe Schritt 7 unten.Die Suite wird ausgeführt.
Die
__exit__()-Methode des Kontextmanagers wird aufgerufen. Wenn eine Ausnahme dazu führte, dass die Suite verlassen wurde, werden ihr Typ, Wert und Traceback als Argumente an__exit__()übergeben. Andernfalls werden dreiNone-Argumente bereitgestellt.Wenn die Suite aufgrund einer Ausnahme verlassen wurde und der Rückgabewert der
__exit__()-Methode falsch war, wird die Ausnahme erneut ausgelöst. Wenn der Rückgabewert wahr war, wird die Ausnahme unterdrückt und die Ausführung wird mit der Anweisung nach derwith-Anweisung fortgesetzt.Wenn die Suite aus einem anderen Grund als einer Ausnahme verlassen wurde, wird der Rückgabewert von
__exit__()ignoriert und die Ausführung wird an der normalen Stelle für die Art des verlassenen Falls fortgesetzt.
Der folgende Code
with EXPRESSION as TARGET:
SUITE
ist semantisch äquivalent zu
manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not exit(manager, *sys.exc_info()):
raise
finally:
if not hit_except:
exit(manager, None, None, None)
Bei mehr als einem Element werden die Kontextmanager verarbeitet, als ob mehrere with-Anweisungen verschachtelt wären.
with A() as a, B() as b:
SUITE
ist semantisch äquivalent zu
with A() as a:
with B() as b:
SUITE
Sie können Kontextmanager mit mehreren Elementen auch über mehrere Zeilen schreiben, wenn die Elemente von Klammern umschlossen sind. Zum Beispiel
with (
A() as a,
B() as b,
):
SUITE
Geändert in Version 3.1: Unterstützung für mehrere Kontextausdrücke.
Geändert in Version 3.10: Unterstützung für die Verwendung von Gruppierungsklammern, um die Anweisung auf mehrere Zeilen aufzuteilen.
8.6. Die match-Anweisung¶
Hinzugefügt in Version 3.10.
Die match-Anweisung wird für Pattern Matching verwendet. Syntax
match_stmt: 'match'subject_expr":" NEWLINE INDENTcase_block+ DEDENT subject_expr: `!star_named_expression` "," `!star_named_expressions`? | `!named_expression` case_block: 'case'patterns[guard] ":" `!block`
Hinweis
Dieser Abschnitt verwendet einfache Anführungszeichen, um Soft Keywords zu bezeichnen.
Pattern Matching nimmt ein Muster als Eingabe (nach case) und einen Subjektwert (nach match) entgegen. Das Muster (das Unterelemente enthalten kann) wird mit dem Subjektwert abgeglichen. Die Ergebnisse sind:
Ein Mustererfolg oder -fehler (auch als Mustererfolg oder -fehler bezeichnet).
Mögliche Bindung von übereinstimmenden Werten an einen Namen. Die Voraussetzungen dafür werden weiter unten erläutert.
Die Schlüsselwörter match und case sind Soft Keywords.
Siehe auch
8.6.1. Überblick¶
Hier ist ein Überblick über den logischen Ablauf einer match-Anweisung:
Der Subjektausdruck
subject_exprwird ausgewertet und ein daraus resultierender Subjektwert erhalten. Wenn der Subjektausdruck ein Komma enthält, wird nach den Standardregeln ein Tupel konstruiert.Jedes Muster in einem
case_blockwird versucht, mit dem Subjektwert abzugleichen. Die spezifischen Regeln für Erfolg oder Misserfolg sind nachfolgend beschrieben. Der Abgleichversuch kann auch einige oder alle eigenständigen Namen innerhalb des Musters binden. Die genauen Regeln für die Musterbindung variieren je nach Mustertyp und sind nachfolgend spezifiziert. Namenbindungen, die während eines erfolgreichen Musterabgleichs vorgenommen werden, überdauern den ausgeführten Block und können nach der match-Anweisung verwendet werden.Hinweis
Bei fehlgeschlagenen Musterabgleichen können einige Untermuster erfolgreich sein. Verlassen Sie sich nicht darauf, dass Bindungen für einen fehlgeschlagenen Abgleich erfolgen. Umgekehrt sollten Sie sich nicht darauf verlassen, dass Variablen nach einem fehlgeschlagenen Abgleich unverändert bleiben. Das genaue Verhalten hängt von der Implementierung ab und kann variieren. Dies ist eine bewusste Entscheidung, die es verschiedenen Implementierungen ermöglicht, Optimierungen hinzuzufügen.
Wenn das Muster erfolgreich ist, wird der entsprechende Guard (falls vorhanden) ausgewertet. In diesem Fall ist garantiert, dass alle Namensbindungen stattgefunden haben.
Wenn der Guard als wahr ausgewertet wird oder fehlt, wird der
blockinnerhalb descase_blockausgeführt.Andernfalls wird der nächste
case_blockwie oben beschrieben versucht.Wenn keine weiteren case-Blöcke vorhanden sind, wird die match-Anweisung abgeschlossen.
Hinweis
Benutzer sollten sich generell niemals darauf verlassen, dass ein Muster ausgewertet wird. Je nach Implementierung kann der Interpreter Werte cachen oder andere Optimierungen verwenden, die wiederholte Auswertungen überspringen.
Eine Beispiel-match-Anweisung
>>> flag = False
>>> match (100, 200):
... case (100, 300): # Mismatch: 200 != 300
... print('Case 1')
... case (100, 200) if flag: # Successful match, but guard fails
... print('Case 2')
... case (100, y): # Matches and binds y to 200
... print(f'Case 3, y: {y}')
... case _: # Pattern not attempted
... print('Case 4, I match anything!')
...
Case 3, y: 200
In diesem Fall ist if flag ein Guard. Lesen Sie mehr darüber im nächsten Abschnitt.
8.6.2. Guards¶
guard: "if" `!named_expression`
Ein guard (der Teil des case ist) muss erfolgreich sein, damit Code innerhalb des case-Blocks ausgeführt wird. Er hat die Form: if gefolgt von einem Ausdruck.
Der logische Fluss eines case-Blocks mit einem guard folgt
Prüfen Sie, ob das Muster im
case-Block erfolgreich war. Wenn das Muster fehlschlägt, wird derguardnicht ausgewertet und der nächstecase-Block wird geprüft.Wenn das Muster erfolgreich ist, werten Sie den
guardaus.Wenn die
guard-Bedingung als wahr ausgewertet wird, wird der case-Block ausgewählt.Wenn die
guard-Bedingung als falsch ausgewertet wird, wird der case-Block nicht ausgewählt.Wenn der
guardwährend der Auswertung eine Ausnahme auslöst, blubbert die Ausnahme nach oben.
Guards dürfen Nebeneffekte haben, da es sich um Ausdrücke handelt. Die Auswertung von Guards muss von der ersten bis zur letzten case-Anweisung nacheinander erfolgen, wobei case-Anweisungen übersprungen werden, deren Muster nicht alle erfolgreich sind. (D. h., die Auswertung von Guards muss in Ordnung erfolgen.) Die Auswertung von Guards muss stoppen, sobald ein case-Block ausgewählt wurde.
8.6.3. Irrefutable Case Blocks¶
Ein irrefutable case-Block ist ein "catch-all" case-Block. Eine match-Anweisung darf höchstens einen irrefutable case-Block haben, und dieser muss der letzte sein.
Ein case-Block gilt als irrefutable, wenn er keinen Guard hat und sein Muster irrefutable ist. Ein Muster gilt als irrefutable, wenn wir allein aus seiner Syntax beweisen können, dass es immer erfolgreich sein wird. Nur die folgenden Muster sind irrefutable:
AS-Muster, deren linke Seite irrefutable ist
ODER-Muster, die mindestens ein irrefutable Muster enthalten
in Klammern gesetzte irrefutable Muster
8.6.4. Patterns¶
Hinweis
Dieser Abschnitt verwendet Grammatiknotationen über EBNF hinaus
die Notation
SEP.RULE+ist eine Kurzform fürRULE (SEP RULE)*die Notation
!RULEist eine Kurzform für eine negative Lookahead-Assertion
Die Top-Level-Syntax für patterns lautet:
patterns:open_sequence_pattern|patternpattern:as_pattern|or_patternclosed_pattern: |literal_pattern|capture_pattern|wildcard_pattern|value_pattern|group_pattern|sequence_pattern|mapping_pattern|class_pattern
Die nachfolgenden Beschreibungen enthalten eine "vereinfachte" Darstellung dessen, was ein Muster tut (dank an Raymond Hettinger für ein Dokument, das die meisten Beschreibungen inspiriert hat). Beachten Sie, dass diese Beschreibungen rein illustrativ sind und nicht die zugrunde liegende Implementierung widerspiegeln müssen. Darüber hinaus decken sie nicht alle gültigen Formen ab.
8.6.4.1. OR Patterns¶
Ein OR-Muster besteht aus zwei oder mehr Mustern, die durch senkrechte Striche | getrennt sind. Syntax
or_pattern: "|".closed_pattern+
Nur das letzte Unter-Muster darf irrefutable sein, und jedes Unter-Muster muss denselben Satz von Namen binden, um Mehrdeutigkeit zu vermeiden.
Ein OR-Muster versucht nacheinander, jedes seiner Unter-Muster an den Subjektwert abzugleichen, bis eines erfolgreich ist. Das OR-Muster gilt dann als erfolgreich. Wenn hingegen keines der Unter-Muster erfolgreich ist, schlägt das OR-Muster fehl.
Vereinfacht ausgedrückt versucht P1 | P2 | ..., P1 abzugleichen. Wenn dies fehlschlägt, versucht es, P2 abzugleichen, und ist sofort erfolgreich, wenn eines davon erfolgreich ist, andernfalls schlägt es fehl.
8.6.4.2. AS Patterns¶
Ein AS-Muster gleicht ein OR-Muster links vom as-Schlüsselwort mit einem Subjekt ab. Syntax
as_pattern:or_pattern"as"capture_pattern
Wenn das OR-Muster fehlschlägt, schlägt das AS-Muster fehl. Andernfalls bindet das AS-Muster das Subjekt an den Namen rechts vom as-Schlüsselwort und ist erfolgreich. capture_pattern kann kein _ sein.
Vereinfacht ausgedrückt gleicht P as NAME mit P ab und setzt bei Erfolg NAME = <subject>.
8.6.4.3. Literal Patterns¶
Ein Literalmuster entspricht den meisten Literalen in Python. Syntax
literal_pattern:signed_number|signed_number"+" NUMBER |signed_number"-" NUMBER |strings| "None" | "True" | "False" signed_number: ["-"] NUMBER
Die Regel strings und das Token NUMBER sind in der Standard-Python-Grammatik definiert. Dreifach-Anführungszeichen-Strings werden unterstützt. Raw-Strings und Byte-Strings werden unterstützt. f-Strings und t-Strings werden nicht unterstützt.
Die Formen signed_number '+' NUMBER und signed_number '-' NUMBER dienen zur Darstellung von komplexen Zahlen; sie erfordern eine reelle Zahl auf der linken und eine imaginäre Zahl auf der rechten Seite. Z.B. 3 + 4j.
Vereinfacht ausgedrückt gelingt LITERAL nur, wenn <subject> == LITERAL. Für die Singletons None, True und False wird der is-Operator verwendet.
8.6.4.4. Capture Patterns¶
Ein Capture-Muster bindet den Subjektwert an einen Namen. Syntax
capture_pattern: !'_' NAME
Ein einzelner Unterstrich _ ist kein Capture-Muster (dies wird durch !'_' ausgedrückt). Er wird stattdessen als wildcard_pattern behandelt.
In einem bestimmten Muster kann ein gegebener Name nur einmal gebunden werden. Z.B. ist case x, x: ... ungültig, während case [x] | x: ... erlaubt ist.
Capture-Muster sind immer erfolgreich. Die Bindung folgt den Gültigkeitsregeln, die durch den Zuweisungsoperator in PEP 572 festgelegt sind; der Name wird zu einer lokalen Variable im nächstgelegenen umschließenden Funktions-Scope, es sei denn, es gibt eine anwendbare global- oder nonlocal-Anweisung.
Vereinfacht ausgedrückt gelingt NAME immer und setzt NAME = <subject>.
8.6.4.5. Wildcard Patterns¶
Ein Wildcard-Muster ist immer erfolgreich (matcht alles) und bindet keinen Namen. Syntax
wildcard_pattern: '_'
_ ist ein Soft-Keyword innerhalb jedes Musters, aber nur innerhalb von Mustern. Es ist wie üblich ein Bezeichner, auch innerhalb von match-Subjektausdrücken, guards und case-Blöcken.
Vereinfacht ausgedrückt gelingt _ immer.
8.6.4.6. Value Patterns¶
Ein Wertemuster repräsentiert einen benannten Wert in Python. Syntax
value_pattern:attrattr:name_or_attr"." NAME name_or_attr:attr| NAME
Der Punktname im Muster wird mit den Standard-Python-Namensauflösungsregeln nachgeschlagen. Das Muster ist erfolgreich, wenn der gefundene Wert gleich dem Subjektwert ist (unter Verwendung des Gleichheitsoperators ==).
Vereinfacht ausgedrückt gelingt NAME1.NAME2 nur, wenn <subject> == NAME1.NAME2.
Hinweis
Wenn derselbe Wert mehrmals in derselben match-Anweisung vorkommt, kann der Interpreter den ersten gefundenen Wert cachen und wiederverwenden, anstatt die gleiche Suche zu wiederholen. Dieser Cache ist streng an eine gegebene Ausführung einer gegebenen match-Anweisung gebunden.
8.6.4.7. Group Patterns¶
Ein Gruppenmuster erlaubt es Benutzern, Klammern um Muster zu setzen, um die beabsichtigte Gruppierung hervorzuheben. Ansonsten hat es keine zusätzliche Syntax. Syntax
group_pattern: "(" pattern ")"
Vereinfacht ausgedrückt hat (P) denselben Effekt wie P.
8.6.4.8. Sequence Patterns¶
Ein Sequenzmuster enthält mehrere Unter-Muster, die gegen Sequenzelemente abgeglichen werden sollen. Die Syntax ähnelt dem Entpacken einer Liste oder eines Tupels.
sequence_pattern: "[" [maybe_sequence_pattern] "]" | "(" [open_sequence_pattern] ")" open_sequence_pattern:maybe_star_pattern"," [maybe_sequence_pattern] maybe_sequence_pattern: ",".maybe_star_pattern+ ","? maybe_star_pattern:star_pattern|patternstar_pattern: "*" (capture_pattern|wildcard_pattern)
Es gibt keinen Unterschied, ob Klammern oder eckige Klammern für Sequenzmuster verwendet werden (d.h. (...) vs. [...]).
Hinweis
Ein einzelnes Muster, das in Klammern ohne nachfolgendes Komma eingeschlossen ist (z.B. (3 | 4)), ist ein Gruppenmuster. Während ein einzelnes Muster, das in eckigen Klammern eingeschlossen ist (z.B. [3 | 4]), immer noch ein Sequenzmuster ist.
Höchstens ein Stern-Unter-Muster darf in einem Sequenzmuster vorhanden sein. Das Stern-Unter-Muster kann an jeder Position auftreten. Wenn kein Stern-Unter-Muster vorhanden ist, ist das Sequenzmuster ein Sequenzmuster mit fester Länge; andernfalls ist es ein Sequenzmuster mit variabler Länge.
Der folgende logische Ablauf beschreibt den Abgleich eines Sequenzmusters gegen einen Subjektwert:
Wenn der Subjektwert keine Sequenz ist [2], schlägt das Sequenzmuster fehl.
Wenn der Subjektwert eine Instanz von
str,bytesoderbytearrayist, schlägt das Sequenzmuster fehl.Die nachfolgenden Schritte hängen davon ab, ob das Sequenzmuster fest oder variabel ist.
Wenn das Sequenzmuster eine feste Länge hat
Wenn die Länge der Subjektsequenz nicht der Anzahl der Unter-Muster entspricht, schlägt das Sequenzmuster fehl.
Die Unter-Muster im Sequenzmuster werden von links nach rechts mit ihren entsprechenden Elementen in der Subjektsequenz abgeglichen. Der Abgleich stoppt, sobald ein Unter-Muster fehlschlägt. Wenn alle Unter-Muster ihre entsprechenden Elemente erfolgreich abgeglichen haben, ist das Sequenzmuster erfolgreich.
Andernfalls, wenn das Sequenzmuster variable Länge hat
Wenn die Länge der Subjektsequenz kleiner ist als die Anzahl der Nicht-Stern-Unter-Muster, schlägt das Sequenzmuster fehl.
Die führenden Nicht-Stern-Unter-Muster werden mit ihren entsprechenden Elementen abgeglichen, wie bei Sequenzen fester Länge.
Wenn der vorherige Schritt erfolgreich ist, gleicht das Stern-Unter-Muster eine Liste ab, die aus den verbleibenden Subjekt-Elementen gebildet wird, unter Ausschluss der verbleibenden Elemente, die den Nicht-Stern-Unter-Mustern nach dem Stern-Unter-Muster entsprechen.
Verbleibende Nicht-Stern-Unter-Muster werden mit ihren entsprechenden Subjekt-Elementen abgeglichen, wie bei einer Sequenz fester Länge.
Hinweis
Die Länge der Subjektsequenz wird über
len()(d.h. über das__len__()-Protokoll) ermittelt. Diese Länge kann vom Interpreter ähnlich wie bei Wertemustern gecacht werden.
Vereinfacht ausgedrückt gelingt [P1, P2, P3, … , P<N>] nur, wenn alles Folgende zutrifft:
prüfen, ob
<subject>eine Sequenz istlen(subject) == <N>P1matcht<subject>[0](beachten Sie, dass dieser Abgleich auch Namen binden kann)P2matcht<subject>[1](beachten Sie, dass dieser Abgleich auch Namen binden kann)… und so weiter für das entsprechende Muster/Element.
8.6.4.9. Mapping Patterns¶
Ein Mapping-Muster enthält ein oder mehrere Schlüssel-Wert-Muster. Die Syntax ähnelt der Konstruktion eines Dictionaries. Syntax
mapping_pattern: "{" [items_pattern] "}" items_pattern: ",".key_value_pattern+ ","? key_value_pattern: (literal_pattern|value_pattern) ":"pattern|double_star_patterndouble_star_pattern: "**"capture_pattern
Höchstens ein Doppelstern-Muster darf in einem Mapping-Muster vorhanden sein. Das Doppelstern-Muster muss das letzte Unter-Muster im Mapping-Muster sein.
Doppelte Schlüssel in Mapping-Mustern sind nicht zulässig. Doppelte Literal-Schlüssel lösen einen SyntaxError aus. Zwei Schlüssel, die ansonsten denselben Wert haben, lösen zur Laufzeit einen ValueError aus.
Der folgende logische Ablauf beschreibt den Abgleich eines Mapping-Musters gegen einen Subjektwert:
Wenn der Subjektwert kein Mapping ist [3], schlägt das Mapping-Muster fehl.
Wenn jeder im Mapping-Muster angegebene Schlüssel im Subjekt-Mapping vorhanden ist und das Muster für jeden Schlüssel mit dem entsprechenden Element des Subjekt-Mappings übereinstimmt, ist das Mapping-Muster erfolgreich.
Wenn doppelte Schlüssel im Mapping-Muster erkannt werden, gilt das Muster als ungültig. Für doppelte Literalwerte wird ein
SyntaxErrorausgelöst; für benannte Schlüssel mit demselben Wert einValueError.
Hinweis
Schlüssel-Wert-Paare werden mit der Zwei-Argumente-Form der get()-Methode des Mapping-Subjekts abgeglichen. Abgeglichene Schlüssel-Wert-Paare müssen bereits im Mapping vorhanden sein und dürfen nicht "on-the-fly" über __missing__() oder __getitem__() erstellt werden.
Vereinfacht ausgedrückt gelingt {KEY1: P1, KEY2: P2, ... } nur, wenn alles Folgende zutrifft:
prüfen, ob
<subject>ein Mapping istKEY1 in <subject>P1matcht<subject>[KEY1]… und so weiter für das entsprechende KEY/Muster-Paar.
8.6.4.10. Class Patterns¶
Ein Klassenmuster repräsentiert eine Klasse und ihre positionsabhängigen und Schlüsselwortargumente (falls vorhanden). Syntax
class_pattern:name_or_attr"(" [pattern_arguments","?] ")" pattern_arguments:positional_patterns[","keyword_patterns] |keyword_patternspositional_patterns: ",".pattern+ keyword_patterns: ",".keyword_pattern+ keyword_pattern: NAME "="pattern
Derselbe Schlüssel darf in Klassenmustern nicht wiederholt werden.
Der folgende logische Ablauf beschreibt den Abgleich eines Klassenmusters gegen einen Subjektwert:
Wenn
name_or_attrkeine Instanz des eingebautentypeist, wirdTypeErrorausgelöst.Wenn der Subjektwert keine Instanz von
name_or_attrist (getestet überisinstance()), schlägt das Klassenmuster fehl.Wenn keine Musterargumente vorhanden sind, ist das Muster erfolgreich. Andernfalls hängen die nachfolgenden Schritte davon ab, ob Schlüsselwort- oder positionsabhängige Muster vorhanden sind.
Für eine Reihe von eingebauten Typen (nachfolgend spezifiziert) wird ein einzelnes positionsabhängiges Unter-Muster akzeptiert, das das gesamte Subjekt abgleicht; für diese Typen funktionieren Schlüsselwortmuster ebenfalls wie für andere Typen.
Wenn nur Schlüsselwortmuster vorhanden sind, werden diese nacheinander wie folgt verarbeitet:
I. Der Schlüssel wird als Attribut des Subjekts nachgeschlagen.
Wenn dies eine Ausnahme außer
AttributeErrorauslöst, blubbert die Ausnahme nach oben.Wenn dies einen
AttributeErrorauslöst, schlägt das Klassenmuster fehl.Andernfalls wird das dem Schlüsselwortmuster zugeordnete Unter-Muster gegen den Attributwert des Subjekts abgeglichen. Wenn dies fehlschlägt, schlägt das Klassenmuster fehl; wenn dies erfolgreich ist, wird der Abgleich mit dem nächsten Schlüsselwort fortgesetzt.
II. Wenn alle Schlüsselwortmuster erfolgreich sind, ist das Klassenmuster erfolgreich.
Wenn positionsabhängige Muster vorhanden sind, werden diese mit dem
__match_args__-Attribut der Klassename_or_attrin Schlüsselwortmuster umgewandelt, bevor abgeglichen wird.I. Das Äquivalent zu
getattr(cls, "__match_args__", ())wird aufgerufen.Wenn dies eine Ausnahme auslöst, blubbert die Ausnahme nach oben.
Wenn der zurückgegebene Wert keine Tupel ist, schlägt die Umwandlung fehl und es wird ein
TypeErrorausgelöst.Wenn es mehr positionsabhängige Muster gibt als
len(cls.__match_args__), wird einTypeErrorausgelöst.Andernfalls wird das positionsabhängige Muster
imithilfe von__match_args__[i]als Schlüsselwort in ein Schlüsselwortmuster umgewandelt.__match_args__[i]muss ein String sein; andernfalls wird einTypeErrorausgelöst.Wenn es doppelte Schlüsselwörter gibt, wird ein
TypeErrorausgelöst.
- II. Sobald alle positionsabhängigen Muster in Schlüsselwortmuster umgewandelt wurden,
erfolgt der Abgleich so, als ob nur Schlüsselwortmuster vorhanden wären.
Für die folgenden eingebauten Typen ist die Handhabung von positionsabhängigen Unter-Mustern anders:
Diese Klassen akzeptieren ein einzelnes positionsabhängiges Argument, und das Muster dort wird gegen das gesamte Objekt abgeglichen und nicht gegen ein Attribut. Zum Beispiel matcht
int(0|1)den Wert0, aber nicht den Wert0.0.
Vereinfacht ausgedrückt gelingt CLS(P1, attr=P2) nur, wenn Folgendes zutrifft:
isinstance(<subject>, CLS)wandelt
P1mithilfe vonCLS.__match_args__in ein Schlüsselwortmuster umFür jedes Schlüsselwortargument
attr=P2hattr(<subject>, "attr")P2matcht<subject>.attr
… und so weiter für das entsprechende Schlüsselwortargument/Muster-Paar.
8.7. Function definitions¶
Eine Funktionsdefinition definiert ein benutzerdefiniertes Funktionsobjekt (siehe Abschnitt Die Standard-Typenhierarchie)
funcdef: [decorators] "def"funcname[type_params] "(" [parameter_list] ")" ["->"expression] ":"suitedecorators:decorator+ decorator: "@"assignment_expressionNEWLINE parameter_list:defparameter(","defparameter)* "," "/" ["," [parameter_list_no_posonly]] |parameter_list_no_posonlyparameter_list_no_posonly:defparameter(","defparameter)* ["," [parameter_list_starargs]] |parameter_list_starargsparameter_list_starargs: "*" [star_parameter] (","defparameter)* ["," [parameter_star_kwargs]] | "*" (","defparameter)+ ["," [parameter_star_kwargs]] |parameter_star_kwargsparameter_star_kwargs: "**"parameter[","] parameter:identifier[":"expression] star_parameter:identifier[":" ["*"]expression] defparameter:parameter["="expression] funcname:identifier
Eine Funktionsdefinition ist eine ausführbare Anweisung. Ihre Ausführung bindet den Funktionsnamen im aktuellen lokalen Namensraum an ein Funktionsobjekt (einen Wrapper um den ausführbaren Code für die Funktion). Dieses Funktionsobjekt enthält einen Verweis auf den aktuellen globalen Namensraum als den globalen Namensraum, der beim Aufruf der Funktion verwendet werden soll.
Die Funktionsdefinition führt den Funktionsrumpf nicht aus; dieser wird erst ausgeführt, wenn die Funktion aufgerufen wird. [4]
Eine Funktionsdefinition kann von einem oder mehreren Decorator-Ausdrücken umschlossen werden. Decorator-Ausdrücke werden ausgewertet, wenn die Funktion definiert wird, im Scope, der die Funktionsdefinition enthält. Das Ergebnis muss ein aufrufbares Objekt sein, das mit dem Funktionsobjekt als einzigem Argument aufgerufen wird. Der zurückgegebene Wert wird anstelle des Funktionsobjekts an den Funktionsnamen gebunden. Mehrere Decorators werden verschachtelt angewendet. Zum Beispiel der folgende Code
@f1(arg)
@f2
def func(): pass
ist grob äquivalent zu
def func(): pass
func = f1(arg)(f2(func))
mit der Ausnahme, dass die ursprüngliche Funktion nicht temporär an den Namen func gebunden wird.
Geändert in Version 3.9: Funktionen können mit jedem gültigen assignment_expression dekoriert werden. Zuvor war die Grammatik viel restriktiver; siehe PEP 614 für Details.
Eine Liste von Typenparametern kann in eckigen Klammern zwischen dem Funktionsnamen und der öffnenden Klammer für ihre Parameterliste angegeben werden. Dies zeigt statischen Typ-Prüfern an, dass die Funktion generisch ist. Zur Laufzeit können die Typenparameter aus dem __type_params__-Attribut der Funktion abgerufen werden. Siehe Generische Funktionen für mehr.
Geändert in Version 3.12: Typenparameterlisten sind neu in Python 3.12.
Wenn ein oder mehrere Parameter die Form parameter = expression haben, sagt man, die Funktion habe "standardmäßige Parameterwerte". Für einen Parameter mit einem Standardwert kann das entsprechende Argument bei einem Aufruf weggelassen werden, in welchem Fall der Standardwert des Parameters eingesetzt wird. Wenn ein Parameter einen Standardwert hat, müssen alle nachfolgenden Parameter bis zum "*" ebenfalls einen Standardwert haben - dies ist eine syntaktische Einschränkung, die nicht durch die Grammatik ausgedrückt wird.
Standardmäßige Parameterwerte werden beim Ausführen der Funktionsdefinition von links nach rechts ausgewertet. Das bedeutet, dass der Ausdruck einmal ausgewertet wird, wenn die Funktion definiert wird, und dass derselbe "vorkomputierte" Wert für jeden Aufruf verwendet wird. Dies ist besonders wichtig zu verstehen, wenn ein Standard-Parameterwert ein veränderliches Objekt ist, wie z.B. eine Liste oder ein Dictionary: Wenn die Funktion das Objekt modifiziert (z.B. durch Anhängen eines Elements an eine Liste), wird der Standard-Parameterwert effektiv modifiziert. Dies ist im Allgemeinen nicht beabsichtigt. Eine Möglichkeit, dies zu umgehen, besteht darin, None als Standardwert zu verwenden und explizit im Rumpf der Funktion darauf zu prüfen, z.B.
def whats_on_the_telly(penguin=None):
if penguin is None:
penguin = []
penguin.append("property of the zoo")
return penguin
Die Semantik von Funktionsaufrufen wird in Abschnitt Calls detaillierter beschrieben. Ein Funktionsaufruf weist allen Parametern, die in der Parameterliste aufgeführt sind, immer Werte zu, entweder aus Positionsargumenten, aus Schlüsselwortargumenten oder aus Standardwerten. Wenn die Form "*identifier" vorhanden ist, wird sie mit einem Tupel initialisiert, das alle überschüssigen Positionsargumente empfängt, standardmäßig das leere Tupel. Wenn die Form "**identifier" vorhanden ist, wird sie mit einer neuen geordneten Zuordnung initialisiert, die alle überschüssigen Schlüsselwortargumente empfängt, standardmäßig eine neue leere Zuordnung desselben Typs. Parameter nach "*" oder "*identifier" sind reine Schlüsselwortparameter und dürfen nur als Schlüsselwortargumente übergeben werden. Parameter vor "/" sind reine positionsabhängige Parameter und dürfen nur als Positionsargumente übergeben werden.
Geändert in Version 3.8: Die /-Syntax für Funktionsparameter kann verwendet werden, um positionsabhängige Parameter anzuzeigen. Siehe PEP 570 für Details.
Parameter können eine Annotation in der Form ": expression" nach dem Parameternamen haben. Jeder Parameter kann eine Annotation haben, auch die der Form *identifier oder **identifier. (Als Sonderfall können Parameter der Form *identifier eine Annotation ": *expression" haben.) Funktionen können eine "Return"-Annotation in der Form "-> expression" nach der Parameterliste haben. Diese Annotationen können beliebige gültige Python-Ausdrücke sein. Das Vorhandensein von Annotationen ändert die Semantik einer Funktion nicht. Siehe Annotationen für weitere Informationen über Annotationen.
Geändert in Version 3.11: Parameter der Form "*identifier" können eine Annotation ": *expression" haben. Siehe PEP 646.
Es ist auch möglich, anonyme Funktionen (Funktionen, die nicht an einen Namen gebunden sind) für die sofortige Verwendung in Ausdrücken zu erstellen. Dies geschieht mithilfe von Lambda-Ausdrücken, die in Abschnitt Lambdas beschrieben werden. Beachten Sie, dass der Lambda-Ausdruck lediglich eine Kurzform für eine vereinfachte Funktionsdefinition ist; eine Funktion, die in einer „def“-Anweisung definiert wurde, kann genau wie eine durch einen Lambda-Ausdruck definierte Funktion weitergegeben oder einem anderen Namen zugewiesen werden. Die „def“-Form ist tatsächlich leistungsfähiger, da sie die Ausführung mehrerer Anweisungen und Annotationen ermöglicht.
Hinweis für Programmierer: Funktionen sind Objekte erster Klasse. Eine „def“-Anweisung, die innerhalb einer Funktionsdefinition ausgeführt wird, definiert eine lokale Funktion, die zurückgegeben oder weitergegeben werden kann. Frei verwendete Variablen in der verschachtelten Funktion können auf die lokalen Variablen der enthaltenden Funktion zugreifen. Details finden Sie in Abschnitt Namensgebung und Bindung.
Siehe auch
- PEP 3107 - Funktionsannotationen
Die ursprüngliche Spezifikation für Funktionsannotationen.
- PEP 484 - Typ-Hints
Definition einer Standardbedeutung für Annotationen: Typ-Hints.
- PEP 526 - Syntax für Variablenannotationen
Möglichkeit, Variablendeklarationen, einschließlich Klassen- und Instanzvariablen, mit Typ-Hints zu versehen.
- PEP 563 - Verzögerte Auswertung von Annotationen
Unterstützung für Vorwärtsreferenzen in Annotationen durch Beibehaltung von Annotationen in Zeichenkettenform zur Laufzeit anstelle einer sofortigen Auswertung.
- PEP 318 - Decorators für Funktionen und Methoden
Funktions- und Methoden-Decorators wurden eingeführt. Klassen-Decorators wurden in PEP 3129 eingeführt.
8.8. Klassendefinitionen¶
Eine Klassendefinition definiert ein Klassenobjekt (siehe Abschnitt Die Standard-Typenhierarchie)
classdef: [decorators] "class"classname[type_params] [inheritance] ":"suiteinheritance: "(" [argument_list] ")" classname:identifier
Eine Klassendefinition ist eine ausführbare Anweisung. Die Vererbungsliste gibt normalerweise eine Liste von Basisklassen an (siehe Metaklassen für fortgeschrittenere Anwendungen), sodass jedes Element in der Liste zu einem Klassenobjekt ausgewertet werden sollte, das Unterklassifizierung ermöglicht. Klassen ohne Vererbungsliste erben standardmäßig von der Basisklasse object; daher,
class Foo:
pass
gleichbedeutend ist mit
class Foo(object):
pass
Die Suite der Klasse wird dann in einem neuen Ausführungsrahmen ausgeführt (siehe Namensgebung und Bindung), wobei ein neu erstellter lokaler Namensraum und der ursprüngliche globale Namensraum verwendet werden. (Normalerweise enthält die Suite meist Funktionsdefinitionen.) Wenn die Ausführung der Suite der Klasse abgeschlossen ist, wird ihr Ausführungsrahmen verworfen, aber ihr lokaler Namensraum wird gespeichert. [5] Ein Klassenobjekt wird dann mithilfe der Vererbungsliste für die Basisklassen und des gespeicherten lokalen Namensraums für das Attributwörterbuch erstellt. Der Klassenname wird in dem ursprünglichen lokalen Namensraum an dieses Klassenobjekt gebunden.
Die Reihenfolge, in der Attribute im Klassenkörper definiert werden, wird im __dict__ der neuen Klasse beibehalten. Beachten Sie, dass dies nur unmittelbar nach der Erstellung der Klasse zuverlässig ist und nur für Klassen, die mithilfe der Definitionssyntax definiert wurden.
Die Klassenerstellung kann mithilfe von Metaklassen stark angepasst werden.
Klassen können auch dekoriert werden: genau wie beim Dekorieren von Funktionen,
@f1(arg)
@f2
class Foo: pass
ist grob äquivalent zu
class Foo: pass
Foo = f1(arg)(f2(Foo))
Die Auswertungsregeln für die Decorator-Ausdrücke sind die gleichen wie für Funktions-Decorators. Das Ergebnis wird dann an den Klassennamen gebunden.
Geändert in Version 3.9: Klassen können mit jedem gültigen assignment_expression dekoriert werden. Zuvor war die Grammatik wesentlich restriktiver; siehe PEP 614 für Details.
Eine Liste von Typ-Parametern kann in eckigen Klammern unmittelbar nach dem Klassennamen angegeben werden. Dies zeigt statischen Typ-Prüfern, dass die Klasse generisch ist. Zur Laufzeit können die Typ-Parameter aus dem Attribut __type_params__ der Klasse abgerufen werden. Siehe Generische Klassen für weitere Informationen.
Geändert in Version 3.12: Typenparameterlisten sind neu in Python 3.12.
Hinweis für Programmierer: In der Klassendefinition definierte Variablen sind Klassenattribute; sie werden von Instanzen gemeinsam genutzt. Instanzattribute können in einer Methode mit self.name = value gesetzt werden. Sowohl Klassen- als auch Instanzattribute sind über die Notation „self.name“ zugänglich, und ein Instanzattribut verbirgt ein Klassenattribut mit demselben Namen, wenn es auf diese Weise zugegriffen wird. Klassenattribute können als Standardwerte für Instanzattribute verwendet werden, aber die Verwendung von veränderlichen Werten kann zu unerwarteten Ergebnissen führen. Deskriptoren können verwendet werden, um Instanzvariablen mit unterschiedlichen Implementierungsdetails zu erstellen.
Siehe auch
- PEP 3115 - Metaklassen in Python 3000
Der Vorschlag, der die Deklaration von Metaklassen in die aktuelle Syntax änderte, sowie die Semantik für die Konstruktion von Klassen mit Metaklassen.
- PEP 3129 - Klassen-Decorators
Der Vorschlag, der Klassen-Decorators einführte. Funktions- und Methoden-Decorators wurden in PEP 318 eingeführt.
8.9. Coroutinen¶
Hinzugefügt in Version 3.5.
8.9.1. Definition von Coroutine-Funktionen¶
async_funcdef: [decorators] "async" "def"funcname"(" [parameter_list] ")" ["->"expression] ":"suite
Die Ausführung von Python-Coroutinen kann an vielen Stellen unterbrochen und fortgesetzt werden (siehe Coroutine). await-Ausdrücke, async for und async with können nur im Körper einer Coroutine-Funktion verwendet werden.
Funktionen, die mit der async def-Syntax definiert werden, sind immer Coroutine-Funktionen, auch wenn sie keine await- oder async-Schlüsselwörter enthalten.
Es ist ein SyntaxError, einen yield from-Ausdruck innerhalb des Körpers einer Coroutine-Funktion zu verwenden.
Ein Beispiel für eine Coroutine-Funktion
async def func(param1, param2):
do_stuff()
await some_coroutine()
Geändert in Version 3.7: await und async sind jetzt Schlüsselwörter; zuvor wurden sie nur innerhalb des Körpers einer Coroutine-Funktion als solche behandelt.
8.9.2. Die async for-Anweisung¶
async_for_stmt: "async" for_stmt
Ein asynchrones Iterable stellt eine __aiter__-Methode bereit, die direkt einen asynchronen Iterator zurückgibt, welcher asynchronen Code in seiner __anext__-Methode aufrufen kann.
Die async for-Anweisung ermöglicht eine bequeme Iteration über asynchrone Iterables.
Der folgende Code
async for TARGET in ITER:
SUITE
else:
SUITE2
Ist semantisch äquivalent zu
iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True
while running:
try:
TARGET = await type(iter).__anext__(iter)
except StopAsyncIteration:
running = False
else:
SUITE
else:
SUITE2
Siehe auch __aiter__() und __anext__() für Details.
Es ist ein SyntaxError, eine async for-Anweisung außerhalb des Körpers einer Coroutine-Funktion zu verwenden.
8.9.3. Die async with-Anweisung¶
async_with_stmt: "async" with_stmt
Ein asynchroner Kontextmanager ist ein Kontextmanager, der in der Lage ist, die Ausführung in seinen enter- und exit-Methoden zu unterbrechen.
Der folgende Code
async with EXPRESSION as TARGET:
SUITE
ist semantisch äquivalent zu
manager = (EXPRESSION)
aenter = type(manager).__aenter__
aexit = type(manager).__aexit__
value = await aenter(manager)
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not await aexit(manager, *sys.exc_info()):
raise
finally:
if not hit_except:
await aexit(manager, None, None, None)
Siehe auch __aenter__() und __aexit__() für Details.
Es ist ein SyntaxError, eine async with-Anweisung außerhalb des Körpers einer Coroutine-Funktion zu verwenden.
Siehe auch
- PEP 492 - Coroutinen mit async und await Syntax
Der Vorschlag, der Coroutinen zu einem eigenständigen Konzept in Python machte und die unterstützende Syntax hinzufügte.
8.10. Typ-Parameter-Listen¶
Hinzugefügt in Version 3.12.
Geändert in Version 3.13: Unterstützung für Standardwerte wurde hinzugefügt (siehe PEP 696).
type_params: "["type_param(","type_param)* "]" type_param:typevar|typevartuple|paramspectypevar:identifier(":"expression)? ("="expression)? typevartuple: "*"identifier("="expression)? paramspec: "**"identifier("="expression)?
Funktionen (einschließlich Coroutinen), Klassen und Typ-Aliase können eine Typ-Parameter-Liste enthalten
def max[T](args: list[T]) -> T:
...
async def amax[T](args: list[T]) -> T:
...
class Bag[T]:
def __iter__(self) -> Iterator[T]:
...
def add(self, arg: T) -> None:
...
type ListOrSet[T] = list[T] | set[T]
Semantisch bedeutet dies, dass die Funktion, Klasse oder der Typ-Alias über eine Typvariable generisch ist. Diese Information wird primär von statischen Typ-Prüfern verwendet, und zur Laufzeit verhalten sich generische Objekte ähnlich wie ihre nicht-generischen Gegenstücke.
Typ-Parameter werden in eckigen Klammern ([]) unmittelbar nach dem Namen der Funktion, Klasse oder des Typ-Alias deklariert. Die Typ-Parameter sind im Geltungsbereich des generischen Objekts zugänglich, aber nicht außerhalb. Daher ist nach einer Deklaration def func[T](): pass der Name T im Modul-Geltungsbereich nicht verfügbar. Im Folgenden werden die Semantiken generischer Objekte genauer beschrieben. Der Geltungsbereich von Typ-Parametern wird mit einer speziellen Funktion (technisch gesehen einem Annotations-Geltungsbereich) modelliert, die die Erstellung des generischen Objekts umschließt.
Generische Funktionen, Klassen und Typ-Aliase haben ein Attribut __type_params__, das ihre Typ-Parameter auflistet.
Typ-Parameter gibt es in drei Arten
typing.TypeVar, eingeführt durch einen einfachen Namen (z. B.T). Semantisch repräsentiert dies einen einzelnen Typ für einen Typ-Prüfer.typing.TypeVarTuple, eingeführt durch einen Namen, dem ein einzelnes Sternchen vorangestellt ist (z. B.*Ts). Semantisch steht dies für ein Tupel beliebiger Anzahl von Typen.typing.ParamSpec, eingeführt durch einen Namen, dem zwei Sternchen vorangestellt sind (z. B.**P). Semantisch steht dies für die Parameter eines Aufrufs.
typing.TypeVar-Deklarationen können Grenzen und Einschränkungen mit einem Doppelpunkt (:) gefolgt von einem Ausdruck definieren. Ein einzelner Ausdruck nach dem Doppelpunkt gibt eine Grenze an (z. B. T: int). Semantisch bedeutet dies, dass der typing.TypeVar nur Typen repräsentieren kann, die eine Unterklasse dieser Grenze sind. Ein Tupel von Ausdrücken in Klammern nach dem Doppelpunkt gibt eine Menge von Einschränkungen an (z. B. T: (str, bytes)). Jedes Mitglied des Tupels sollte ein Typ sein (auch dies wird zur Laufzeit nicht erzwungen). Eingeschränkte Typvariablen können nur einen der Typen aus der Liste der Einschränkungen annehmen.
Für typing.TypeVars, die mithilfe der Typ-Parameter-Listen-Syntax deklariert werden, werden die Grenzen und Einschränkungen nicht bei der Erstellung des generischen Objekts ausgewertet, sondern erst, wenn auf den Wert explizit über die Attribute __bound__ und __constraints__ zugegriffen wird. Um dies zu erreichen, werden die Grenzen oder Einschränkungen in einem separaten Annotations-Geltungsbereich ausgewertet.
typing.TypeVarTuples und typing.ParamSpecs können keine Grenzen oder Einschränkungen haben.
Alle drei Arten von Typ-Parametern können auch einen Standardwert haben, der verwendet wird, wenn der Typ-Parameter nicht explizit angegeben wird. Dies wird durch Anhängen eines einzelnen Gleichheitszeichens (=) gefolgt von einem Ausdruck hinzugefügt. Ähnlich wie die Grenzen und Einschränkungen von Typvariablen wird der Standardwert nicht bei der Erstellung des Objekts ausgewertet, sondern erst, wenn auf das Attribut __default__ des Typ-Parameters zugegriffen wird. Zu diesem Zweck wird der Standardwert in einem separaten Annotations-Geltungsbereich ausgewertet. Wenn für einen Typ-Parameter kein Standardwert angegeben wird, wird das Attribut __default__ auf das spezielle Sentinel-Objekt typing.NoDefault gesetzt.
Das folgende Beispiel zeigt die vollständige Menge der zulässigen Typ-Parameter-Deklarationen
def overly_generic[
SimpleTypeVar,
TypeVarWithDefault = int,
TypeVarWithBound: int,
TypeVarWithConstraints: (str, bytes),
*SimpleTypeVarTuple = (int, float),
**SimpleParamSpec = (str, bytearray),
](
a: SimpleTypeVar,
b: TypeVarWithDefault,
c: TypeVarWithBound,
d: Callable[SimpleParamSpec, TypeVarWithConstraints],
*e: SimpleTypeVarTuple,
): ...
8.10.1. Generische Funktionen¶
Generische Funktionen werden wie folgt deklariert
def func[T](arg: T): ...
Diese Syntax ist äquivalent zu
annotation-def TYPE_PARAMS_OF_func():
T = typing.TypeVar("T")
def func(arg: T): ...
func.__type_params__ = (T,)
return func
func = TYPE_PARAMS_OF_func()
Hier gibt annotation-def einen Annotations-Geltungsbereich an, der zur Laufzeit nicht tatsächlich an einen Namen gebunden ist. (Eine weitere Erlaubnis wird erteilt: Die Syntax durchläuft keinen Attributzugriff auf das Modul typing, sondern erstellt direkt eine Instanz von typing.TypeVar.)
Die Annotationen von generischen Funktionen werden innerhalb des Annotations-Geltungsbereichs ausgewertet, der für die Deklaration der Typ-Parameter verwendet wird, jedoch nicht die Standardwerte und Decorators der Funktion.
Das folgende Beispiel veranschaulicht die Geltungsbereichsregeln für diese Fälle sowie für zusätzliche Arten von Typ-Parametern
@decorator
def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
...
Abgesehen von der verzögerten Auswertung der TypeVar-Grenze ist dies äquivalent zu
DEFAULT_OF_arg = some_default
annotation-def TYPE_PARAMS_OF_func():
annotation-def BOUND_OF_T():
return int
# In reality, BOUND_OF_T() is evaluated only on demand.
T = typing.TypeVar("T", bound=BOUND_OF_T())
Ts = typing.TypeVarTuple("Ts")
P = typing.ParamSpec("P")
def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg):
...
func.__type_params__ = (T, Ts, P)
return func
func = decorator(TYPE_PARAMS_OF_func())
Die großgeschriebenen Namen wie DEFAULT_OF_arg sind zur Laufzeit nicht tatsächlich gebunden.
8.10.2. Generische Klassen¶
Generische Klassen werden wie folgt deklariert
class Bag[T]: ...
Diese Syntax ist äquivalent zu
annotation-def TYPE_PARAMS_OF_Bag():
T = typing.TypeVar("T")
class Bag(typing.Generic[T]):
__type_params__ = (T,)
...
return Bag
Bag = TYPE_PARAMS_OF_Bag()
Auch hier gibt annotation-def (kein echtes Schlüsselwort) einen Annotations-Geltungsbereich an, und der Name TYPE_PARAMS_OF_Bag ist zur Laufzeit nicht tatsächlich gebunden.
Generische Klassen erben implizit von typing.Generic. Die Basisklassen und Schlüsselwortargumente von generischen Klassen werden innerhalb des Typ-Geltungsbereichs für die Typ-Parameter ausgewertet, und Decorators werden außerhalb dieses Geltungsbereichs ausgewertet. Dies wird durch folgendes Beispiel veranschaulicht
@decorator
class Bag(Base[T], arg=T): ...
Dies ist äquivalent zu
annotation-def TYPE_PARAMS_OF_Bag():
T = typing.TypeVar("T")
class Bag(Base[T], typing.Generic[T], arg=T):
__type_params__ = (T,)
...
return Bag
Bag = decorator(TYPE_PARAMS_OF_Bag())
8.10.3. Generische Typ-Aliase¶
Die type-Anweisung kann auch verwendet werden, um einen generischen Typ-Alias zu erstellen
type ListOrSet[T] = list[T] | set[T]
Abgesehen von der verzögerten Auswertung des Wertes ist dies äquivalent zu
annotation-def TYPE_PARAMS_OF_ListOrSet():
T = typing.TypeVar("T")
annotation-def VALUE_OF_ListOrSet():
return list[T] | set[T]
# In reality, the value is lazily evaluated
return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
ListOrSet = TYPE_PARAMS_OF_ListOrSet()
Hier gibt annotation-def (kein echtes Schlüsselwort) einen Annotations-Geltungsbereich an. Die großgeschriebenen Namen wie TYPE_PARAMS_OF_ListOrSet sind zur Laufzeit nicht tatsächlich gebunden.
8.11. Annotationen¶
Geändert in Version 3.14: Annotationen werden jetzt standardmäßig verzögert ausgewertet.
Variablen und Funktionsparameter können Annotationen tragen, die durch Hinzufügen eines Doppelpunkts nach dem Namen gefolgt von einem Ausdruck erstellt werden
x: annotation = 1
def f(param: annotation): ...
Funktionen können auch eine Rückgabeannotation nach einem Pfeil tragen
def f() -> annotation: ...
Annotationen werden konventionell für Typ-Hints verwendet, dies wird jedoch nicht von der Sprache erzwungen, und im Allgemeinen können Annotationen beliebige Ausdrücke enthalten. Die Anwesenheit von Annotationen ändert die Laufzeitsemantik des Codes nicht, es sei denn, es wird ein Mechanismus verwendet, der die Annotationen introspektiert und nutzt (wie dataclasses oder functools.singledispatch()).
Standardmäßig werden Annotationen verzögert in einem Annotations-Geltungsbereich ausgewertet. Das bedeutet, dass sie nicht ausgewertet werden, wenn der Code, der die Annotation enthält, ausgewertet wird. Stattdessen speichert der Interpreter Informationen, die verwendet werden können, um die Annotation später bei Bedarf auszuwerten. Das Modul annotationlib bietet Werkzeuge zur Auswertung von Annotationen.
Wenn die Future-Anweisung from __future__ import annotations vorhanden ist, werden alle Annotationen stattdessen als Zeichenketten gespeichert
>>> from __future__ import annotations
>>> def f(param: annotation): ...
>>> f.__annotations__
{'param': 'annotation'}
Dieses Future-Statement wird in einer zukünftigen Version von Python veraltet und entfernt, aber nicht bevor Python 3.13 sein Lebensende erreicht hat (siehe PEP 749). Wenn es verwendet wird, ist es für Introspektionswerkzeuge wie annotationlib.get_annotations() und typing.get_type_hints() weniger wahrscheinlich, Annotationen zur Laufzeit auflösen zu können.
Fußnoten