Generator als Funktion argument
Kann mir jemand erklären, warum die übergabe eines generator, der nur positionelle argument an eine Funktion zu haben scheint, Besondere Regeln?
Wenn wir haben:
>>> def f(*args):
>>> print "Success!"
>>> print args
- Dies funktioniert, wie erwartet.
>>> f(1, *[2]) Success! (1, 2)
- Diese nicht funktioniert, wie erwartet.
>>> f(*[2], 1) File "<stdin>", line 1 SyntaxError: only named arguments may follow *expression
- Dies funktioniert, wie erwartet
>>> f(1 for x in [1], *[2]) Success! (generator object <genexpr> at 0x7effe06bdcd0>, 2)
- Dies funktioniert, aber ich verstehe nicht warum. Sollte es nicht scheitern, in der gleichen Weise wie 2)
>>> f(*[2], 1 for x in [1]) Success! (generator object <genexpr> at 0x7effe06bdcd0>, 2)
f((*[2, 3]), 1)
gibt syntax-Fehler bei *
- könnten Sie bitte erläutern Sie Ihre Anregung weiter? Auch, die Frage ist nicht, "wie es funktioniert", sondern "warum funktioniert es so?"Nicht ein exaktes Duplikat, aber sehr ähnlich aus: stackoverflow.com/questions/12720450/.... TL;DR wie es scheint, ist eine Implementierung detail, es funktioniert einfach so.
Hinweis: Fall 2 sollte in python 3.5+ (aufgrund der PEP 448)
Python 3.5 raus ist, und er erzählt nun, dass der Fall 3 (eigentlich auch der Fall 4) wurde behoben. What ' s new in Python 3.5
InformationsquelleAutor DeTeReR | 2015-09-11
Du musst angemeldet sein, um einen Kommentar abzugeben.
Beide 3. und 4. sollte werden syntax-Fehler, die auf alle Python-Versionen. Aber Sie haben einen Fehler gefunden und betrifft die Python-Versionen 2.5 - 3.4, und die anschließend veröffentlicht auf der Python-Problem-tracker. Weil der bug, ein unparenthesized generator expression angenommen wurde, als argument an eine Funktion, wenn es war, begleitet nur von
*args
- und/oder**kwargs
. Während Python 2.6+ erlaubt beiden Fällen 3. und 4., Python 2.5 nur zulässig, Fall 3. - und doch waren beide gegen die dokumentiert Grammatik:d.h. die Dokumentation sagt, dass ein Funktionsaufruf besteht aus
primary
(der Ausdruck, der ausgewertet wird, um ein callable), gefolgt von in Klammern, die entweder ein argument-Liste oder nur ein unparenthesized generator-Ausdruck;und in der argument-Liste, alle generator-Ausdrücke müssen in Klammern.
Dieser bug (obwohl es scheint, es sei noch nicht bekannt), war fest in Python 3.5 prereleases. In Python 3.5 Klammern sind immer erforderlich, um einen generator-Ausdruck, es sei denn, es ist das einzige argument für die Funktion:
Dies ist nun dokumentiert in der Was ist Neu in Python 3.5, Dank DeTeReR entdecken dieser Fehler.
Analyse der Fehler
Gab es eine änderung zu Python 2.6 erlaubt die Verwendung von Schlüsselwort-Argumente nach
*args
:Jedoch die Python 2.6 Grammatik macht keinen Unterschied zwischen keyword-Argumente, positionale Argumente, oder bare-generator-Ausdrücke - Sie sind alle vom Typ
argument
an den parser.Als pro Python-Regeln, ein generator-Ausdruck muss in Klammern, wenn er nicht das alleinige argument für die Funktion. Dies ist validiert in der
Python/ast.c
:Allerdings ist diese Funktion nicht nicht betrachten die
*args
an alle - es speziell nur für den normalen positions-und Schlüsselwort-Argumente Argumente.Weiter unten in die gleiche Funktion, es wird eine Fehlermeldung generiert, für non-keyword arg after keyword arg:
Aber das gilt wieder für Argumente, die nicht unparenthesized generator-Ausdrücke als belegt durch die
else if
- Anweisung:Somit eine unparenthesized generator expression durfte slip-pass.
Nun in Python 3.5 kann man die
*args
irgendwo in einer Funktion aufgerufen wird, so dassdie Grammatik wurde geändert, um Platz für dieses:
und
und die
- Schleife geändert wurde zu
Damit beheben des Fehlers.
Jedoch die unbeabsichtigte änderung ist, dass der gültige aussehende Konstruktionen
und
wo ein unparenthesized generator vor
*args
oder**kwargs
jetzt aufgehört zu arbeiten.Suchen Sie diese Fehler, ich habe versucht, verschiedene Python-Versionen. Bei 2.5 würden Sie bekommen
SyntaxError
:Und dies konnte behoben werden, bevor eine Vorabversion von Python 3.5:
Jedoch die in Klammern gesetzten generator-Ausdruck, es funktioniert in Python 3.5, aber es funktioniert nicht, nicht in Python 3.4:
- Und das ist der clue. In Python 3.5
*splatting
ist verallgemeinert; Sie können es verwenden, irgendwo in einer Funktion aufrufen:Also den eigentlichen Fehler (generator arbeiten mit
*star
ohne Klammern) war zwar Feste in Python 3.5, und der bug konnte gefunden werden, dass das, was geändert zwischen Python 3.4 und 3.5guter Punkt, der in 3.4 die Klammern - Ausdruck gibt einen Fehler
huh? Läuft auf 3.4.3:
f(*[1], 1 for x in [1])
=>(<generator object <genexpr> at 0x7fa56c889288>, 1)
für x in [1])) syntax-Fehler, die auf Python 3.4. Es gilt in Python 3.5.
Ich würde gild diese Antwort, wenn ich könnte, Dank, einschließlich der entsprechenden C-Quelle!
InformationsquelleAutor Antti Haapala