2016-03-22 5 views
2
# why is the following invalid 
x = (k, v for k, v in some_dict.items()) 

# but if we wrap the expression part in parentheses it works 
x = ((k, v) for k, v in some_dict.items()) 

Ich schaute durch die Dokumentation und schien nichts dabei zu finden? Was könnte den Parser so verwirren, dass die Syntax nicht erlaubt ist? Trotz etwas noch komplexere Arbeits:Warum sind nicht-behandelte Tupel in Generatoren im Ausdrucksfeld nicht erlaubt?

# k, v somehow confuses the parser but this doesnt??? 
x = ('%s:%s:%s' % (k, v, k) for k, v in some_dict.items()) 

wie kommen wir nicht brauchen %s:%s:%s % (k, v, k) mit einer umgebenden Klammern wickeln auch dann?

Antwort

5

Blick auf x = (k, v for k, v in some_dict.items()):

x = (k, v for k, v in some_dict.items()) 
x = ((k, v) for k, v in some_dict.items()) 
x = (k, (v for k, v in some_dict.items())) 

Klammern nötig sind, um die Mehrdeutigkeit zu entfernen.

x = ('%s:%s:%s' % (k, v, k) for k, v in some_dict.items()) erfordert auch Klammern:

x = ('%s:%s:%s' % k, v, k for k, v in some_dict.items()) 
x = ('%s:%s:%s' % k, (v, k) for k, v in some_dict.items()) 
x = ('%s:%s:%s' % (k, v, k) for k, v in some_dict.items()) 

Es ist einfach so passiert, dass Sie schon genug Klammern hatten die Mehrdeutigkeit dort in einer Art und Weise zu lösen, die sie in der erwarteten Art und Weise ablaufen.

3

Python-Parser analysiert diese

x = (k, v for k, v in some_dict.items()) 

als Tupel enthält k und dem Generator Ausdruck:

v for k, v in some_dict.items() 

Aber dies ist kein gültiger Generator Ausdruck: es sein muss, wie PEP 289 puts it:

direkt in einem Satz von Klammern und kann keine Komm. haben nicht direkt in einer Reihe von Klammern ein auf beiden Seiten

Was Python als Generator ist hier sieht, und tut auf der einen Seite ein Komma, so dass es illegal ist.


Der Grund dafür ist, weil der Parser (absichtlich) sehr einfach ist. Insbesondere ist es ein LL (1) -Parser, der es bedeutet:

  • Scannt Token von links nach rechts;
  • Betrachtet das aktuelle Token und das nächste (ein Token von Lookahead); und
  • eine Entscheidung trifft, so schnell wie möglich über das, was ein Ausdruck bedeutet

So wird es zum aktuellen Token k zu sein, und sieht, dass die nächste ist ein Komma. Dies ist ein Tupel, und es bleibt mit dieser Entscheidung. Es sieht nur die for später (wenn das aktuelle Token ist v), so dass ein Generator Ausdruck innerhalb das Tupel wird. Der Parser wird nicht zurückverfolgt, um zu sehen, ob es einen möglichen legalen Syntaxanalyse-Ausdruck gibt (da der Tupel in dem Generatorausdruck vorgesehen ist, aber nicht immer vorhanden ist), er wirft sofort einen Fehler auf.

+0

Warum wäre 'v für k, v in some_dict.items()' kein gültiger Generatorausdruck? Ich sehe nichts falsch daran. – Wombatz

+0

@Wombatz siehe das Zitat aus der PEP; Um ein Tupel mit einem Wert und einem Genexp zu erstellen, müssen Sie das Genxp in einen anderen Klammersatz einfügen. Aus dem Zusammenhang heraus ist dieses Genexp in Ordnung, aber in diesem Zusammenhang ist es ein Fehler. Das ist das Gleiche, als ob Sie es als Argument für eine Funktion verwenden, die Sie auch einige andere Argumente übergeben - Sie können 'sum (f (x) für x in ...)' tun, müssen aber 'sum ((f (x) für x in ....), start = '') '. – lvc

+0

"Aus dem Zusammenhang, das genexp ist in Ordnung". Das habe ich gemeint, danke für die Klarstellung. Es schien, dass der Ausdruck selbst nicht gültig ist. – Wombatz

Verwandte Themen