Kann jemand erklären, warum das Übergeben eines Generators als einziges Positionsargument an eine Funktion spezielle Regeln zu haben scheint?
Wenn wir haben:
>>> def f(*args):
>>> print "Success!"
>>> print args
Dies funktioniert wie erwartet.
>>> f(1, *[2]) Success! (1, 2)
Dies funktioniert nicht 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)
Das funktioniert, aber ich verstehe nicht warum. Sollte es nicht genauso scheitern wie 2)
>>> f(*[2], 1 for x in [1]) Success! (generator object <genexpr> at 0x7effe06bdcd0>, 2)
python
python-2.7
syntax
generator-expression
DeTeReR
quelle
quelle
f((*[2, 3]), 1)
gibt Syntaxfehler bei*
- könnten Sie bitte Ihren Vorschlag weiter erläutern? Die Frage ist auch nicht "wie es funktioniert", sondern "warum funktioniert es so?"Antworten:
Sowohl 3. als auch 4. sollten in allen Python-Versionen Syntaxfehler sein. Sie haben jedoch einen Fehler gefunden, der die Python-Versionen 2.5 - 3.4 betrifft und der anschließend im Python-Issue-Tracker veröffentlicht wurde . Aufgrund des Fehlers wurde ein nicht in Klammern stehender Generatorausdruck als Argument für eine Funktion akzeptiert, wenn er nur von
*args
und / oder begleitet wurde**kwargs
. Während Python 2.6+ beide Fälle 3. und 4. erlaubte, erlaubte Python 2.5 nur Fall 3. - doch beide waren gegen die dokumentierte Grammatik :dh die Dokumentation sagt ein Funktionsaufruf besitzt
primary
(der Ausdruck, der zu einer auswertet aufrufbaren), gefolgt von der in Klammern entweder einer Argumentliste oder nur ein unparenthesized Generator Ausdruck; und innerhalb der Argumentliste müssen alle Generatorausdrücke in Klammern stehen.Dieser Fehler (obwohl er anscheinend nicht bekannt war) wurde in Python 3.5-Vorabversionen behoben. In Python 3.5 sind immer Klammern um einen Generatorausdruck erforderlich, es sei denn, dies ist das einzige Argument für die Funktion:
Dies ist jetzt in den Neuigkeiten in Python 3.5 dokumentiert , da DeTeReR diesen Fehler entdeckt hat.
Analyse des Fehlers
In Python 2.6 wurde eine Änderung vorgenommen, die die Verwendung von Schlüsselwortargumenten nach
*args
folgenden Bedingungen ermöglichte :Die Python 2.6- Grammatik unterscheidet jedoch nicht zwischen Schlüsselwortargumenten, Positionsargumenten oder bloßen Generatorausdrücken - sie sind alle vom Typ
argument
für den Parser.Gemäß den Python-Regeln muss ein Generatorausdruck in Klammern gesetzt werden, wenn dies nicht das einzige Argument für die Funktion ist. Dies wird validiert in
Python/ast.c
:Allerdings ist diese Funktion nicht die betrachtet
*args
überhaupt - es speziell schaut nur für gewöhnliche Positionsargumente und Keyword - Argumente.Weiter unten in derselben Funktion wird eine Fehlermeldung für Nicht-Schlüsselwort arg nach Schlüsselwort arg generiert :
Dies gilt jedoch wiederum für Argumente, bei denen es sich nicht um nicht parästhesierte Generatorausdrücke handelt, wie aus der
else if
Aussage hervorgeht :Somit wurde ein nicht parästhesierter Generatorausdruck passieren gelassen.
In Python 3.5 kann man jetzt die
*args
beliebige Stelle in einem Funktionsaufruf verwenden, daher wurde die Grammatik geändert, um dies zu berücksichtigen:und
und die
for
Schleife wurde geändert inSo wird der Fehler behoben.
Die unbeabsichtigte Änderung ist jedoch, dass die Konstruktionen gültig aussehen
und
wo ein nicht parästhesierter Generator vorausgeht
*args
oder**kwargs
jetzt nicht mehr funktioniert.Um diesen Fehler zu finden, habe ich verschiedene Python-Versionen ausprobiert. In 2.5 erhalten Sie
SyntaxError
:Und dies wurde vor einer Vorabversion von Python 3.5 behoben:
Der Generatorausdruck in Klammern funktioniert jedoch in Python 3.5, jedoch nicht in Python 3.4:
Und das ist der Hinweis. In Python 3.5
*splatting
ist das verallgemeinert; Sie können es überall in einem Funktionsaufruf verwenden:Der eigentliche Fehler (Generator, der
*star
ohne Klammern arbeitet) wurde tatsächlich in Python 3.5 behoben, und der Fehler konnte darin gefunden werden, was sich zwischen Python 3.4 und 3.5 geändert hatquelle
f(*[1], 1 for x in [1])
=>(<generator object <genexpr> at 0x7fa56c889288>, 1)
f(*[1], (1 for x in [1]))
ist ein Syntaxfehler in Python 3.4. Es ist gültig in Python 3.5.