Die Python-Sprache (insbesondere 3.x) ermöglicht das sehr allgemeine Entpacken von Iterables, ein einfaches Beispiel dafür
a, *rest = 1, 2, 3
Im Laufe der Jahre wurde dieses Auspacken schrittweise verallgemeinert (siehe z. B. PEP 3132 und PEP 448 ), so dass es unter immer mehr Umständen verwendet werden kann. Daher war ich überrascht zu entdecken, dass die folgende Syntax in Python 3.6 ungültig ist (und dies auch in Python 3.7 bleibt):
def f():
rest = [2, 3]
return 1, *rest # Invalid
Ich kann es zum Laufen bringen, indem ich das zurückgegebene Tupel wie folgt in Klammern kapsle:
def f():
rest = [2, 3]
return (1, *rest) # Valid
Die Tatsache, dass ich dies in einer return
Aussage verwende, scheint wichtig zu sein
t = 1, *rest
ist in der Tat legal und führt zum gleichen mit und ohne Klammern.
Wurde dieser Fall von den Python-Entwicklern einfach vergessen, oder gibt es einen Grund, warum dieser Fall eine ungültige Syntax ist?
Warum es mich interessiert
Dies bricht einen wichtigen Vertrag, den ich mit der Python-Sprache zu haben glaubte. Betrachten Sie die folgende (auch gültige) Lösung:
def f():
rest = [2, 3]
t = 1, *rest
return t
Wenn ich Code wie diesen habe, halte ich ihn normalerweise t
für einen temporären Namen, den ich loswerden sollte, indem ich ihn einfach t
in der unteren Zeile durch seine Definition ersetze . In diesem Fall führt dies jedoch zu einem ungültigen Code
def f():
rest = [2, 3]
return 1, *rest
Es ist natürlich keine große Sache, Klammern um den Rückgabewert setzen zu müssen, aber normalerweise werden zusätzliche Klammern nur benötigt, um zwischen mehreren möglichen Ergebnissen zu unterscheiden (Gruppierung). Hier ist dies nicht der Fall, da das Weglassen der Klammern kein anderes unerwünschtes Verhalten hervorruft, sondern überhaupt kein Verhalten.
Aktualisieren
Seit Python 3.8 (siehe Punkt 7 in dieser Liste ) ist die oben beschriebene verallgemeinerte Syntax jetzt gültig.
t = *rest
es ungültig ist. Auchreturn *rest
undt = *rest
stellt kein tatsächliches Auspacken dar, so dass ich es nicht als Problem empfinde, dass dies nicht erlaubt ist. Wenn es erlaubt wäre,*rest
wäre allein nur eine verwirrende Syntax fürtuple(rest)
.return
. Das Auspacken ist auch in einemyield
Argument, einem Index, der RHS einer erweiterten Zuordnung (aber nicht einer regulären Zuordnung) und rechts von derin
in einerfor
Anweisung verboten, obwohl in all diesen Positionen nicht parenthesierte Tupel zulässig sind, da die Syntax für diese Dinge verwendetexpression_list
stattstarred_expression
.t = *rest
undt = *rest,
. Letzteres ist gültig.Antworten:
Ich vermute, dass dies ein Unfall ist, basierend auf den Kommentaren aus diesem Commit für Python 3.2.
Dieses Commit ermöglichte es dem Zuweisungsausdruck, eine
testlist_star_expr
Produktion aufzunehmen (was das nicht entpackte Entpacken ermöglicht), ließ jedoch die return-Anweisung einetestlist
Produktion übernehmen. Ich vermute, dass das Commit dies gerade verpasst hat (und möglicherweise auch an anderen Orten, aber ich konzentriere mich vorerst auf diereturn_stmt
Produktion).Ich habe die Python-Grammatik / Grammatik-Datei geändert, um dies zu ermöglichen. Alle Tests bestehen weiterhin, einschließlich der in der
test_grammar.py
Datei enthaltenen (dies scheint jedoch nicht besonders erschöpfend zu sein).Wenn Sie neugierig sind, ist dies die Änderung, die ich vorgenommen habe . Fühlen Sie sich frei, meine Gabel zu klonen oder herunterzuladen .
UPDATE: Ich habe ein bpo-Problem und eine Pull-Anfrage für das Auspacken von Rückgabe (und Ertrag) eingereicht .
quelle
yield_stmt
Produktion) betrachten, bevor ich es weitersende .