2012-09-30 18 views
14

Ich schreibe einen Parser, und in den Prozess der Fehlersuche, fand ich, dass es scheint, diese Rechts Python ist:Was bedeutet diese Python-Anweisung?

for [] in [[]]: print 0 

und so ist diese (!):

for [][:] in [[]]: print 0 

I Geben Sie dem Parser nicht die Schuld dafür, dass er verwirrt wurde ... Ich bin Ich habe Probleme herauszufinden, wie ich das interpretiere!

Was genau bedeutet diese Aussage?

+0

Google für Sequenz Auspacken funktioniert. Sollte es erklären. – hendrik

Antwort

14

In Bezug auf die Ausführung: nichts.

Die Schleife for selbst führt eine Schleife über eine leere Liste, so dass keine Iterationen stattfinden.

Und das ist eine gute Sache, denn die for [] bedeutet: jeden Eintrag in der Schleife zu 0 Variablen zuweisen. Der letzte Teil ist wahrscheinlich, was Sie verwirrt.

Die Anweisung ist zulässig, da die target token token_list es Ihnen ermöglicht, die Werte in einer Sequenz einer gleich großen Sequenz von Variablennamen zuzuordnen; Wir nennen das Tupel-Entpacken. Im Folgenden sind weitere nützliche Beispiele für Ziellisten, in Zuordnung und Löschung:

(a, b, c) = range(3) 
del a, b, c 

Sie können in einer for Schleife das gleiche tun:

nested = [[1,2,3], [4,5,6]] 
for a, b, c in nested: 
    print nested 

Sie beide Tupel und Listen für die target_list Token verwenden können Dies ist auch zulässig:

[a, b] = (1, 2) 

In Python kann eine Liste jedoch leer sein. Somit ist die folgende Recht jedoch nicht sensical:

[] = [] 

und schließlich, so ist dies:

nested_empty = [[], [], []] 
for [] in nested_empty: 
    pass 

Mehr Spaß mit Ziellisten:

[][:] = [1, 2, 3] 

Nun ist die links- Hand-Seite verwendet eine Scheibe in der Zuweisung. Aus der Dokumentation:

Wenn das Ziel ein Slicing ist: Der primäre Ausdruck in der Referenz wird ausgewertet. Es sollte ein veränderbares Sequenzobjekt (wie eine Liste) ergeben. Das zugeordnete Objekt sollte ein Sequenzobjekt desselben Typs sein. Als nächstes werden die unteren und oberen gebundenen Ausdrücke ausgewertet, sofern sie vorhanden sind; Standardwerte sind Null und die Länge der Sequenz. Die Grenzen sollten zu (kleinen) ganzen Zahlen ausgewertet werden. Wenn eine der beiden Bindungen negativ ist, wird die Länge der Sequenz hinzugefügt. Die resultierenden Grenzen werden abgeschnitten, um zwischen Null und der Länge der Sequenz einschließlich zu liegen. Schließlich wird das Sequenzobjekt aufgefordert, das Segment durch die Elemente der zugewiesenen Sequenz zu ersetzen. Die Länge der Schicht kann sich von der Länge der zugewiesenen Sequenz unterscheiden, wodurch sich die Länge der Zielsequenz ändert, wenn das Objekt dies zulässt.

So hier sind wir nicht mehr mit Tupel-Entpacken; Stattdessen ersetzen wir einen Abschnitt der linken Liste durch die rechte Liste. Da in unserem Beispiel die linke Liste ein anonymen Listenliteral ist, ist die resultierende geänderte Liste wieder verloren.

Aber weil eine solche Zuordnung für Schleife in eine auch legal ist, ist das Folgende Rechts Syntax, wenn auch eher nicht-sensical:

for [][:] in [range(i) for i in range(10)]: print 0 
+0

Ah, das erklärt warum 'for [] in [[]]: print 0' funktioniert, aber was ist mit' für [] [:] in [[]]: print 0'? Wie ist das legal/was bedeutet das? – Mehrdad

+2

Die Liste ist nicht leer. Es enthält ein Element, das die leere Liste ist. Daher wird 0 gedruckt. –

+0

@Mehrdad: Die linke 'target_list' kann eine Slice-Zuweisung sein. 'alist [1: 2]' = somelist' ersetzt die durch '[1: 2]' angezeigte Scheibe durch die Werte von 'somelist'. Ein Slice ist also ein gültiger linksseitiger Ausdruck für eine Zuweisung, der auch in einer Schleife gültig ist. –

1
for [] in [[]]: print 0 

es entspricht:

In [44]: for [x,y] in [[1,2],[3,4],[5,6]]: # or even (x,y) will work 
    print x,y 
    ....:  
    ....:  
1 2 
3 4 
5 6 

aber die erste erwartet, dass kein Wert aus der Liste zurückgegeben wird, dh die Werte in der Liste sind entweder leer oder ihre len() i s 0.

Sie können () dort nicht verwenden, da es nicht gültig ist.

weil in Python, können Sie ALSs wie folgt vergeben:

In [56]: x,y=[1,2]  #this means that the expression on RHS should return two values 
         # (x,y)=[1,2] or x,y=(1,2) or (x,y)=(1,2) all are valid 

In [57]: x 
Out[57]: 1 

In [58]: y 
Out[58]: 2 


In [62]: x,y='ab'  #assign a to x and b to y 

In [63]: x 
Out[63]: 'a' 

In [64]: y 
Out[64]: 'b' 
1

Hier ist meine beste Vermutung:

for [] in [[]] Mittel „für jede Instanz von [] (eine leere Liste Objekt) in dieser Liste [[]] (eine Liste mit genau einem Element, das eine leere Liste Objekt) ist, print 0.

im zweiten Fall, denke ich [:] rufen nur slice() w mit allen Standardwerten, die einfach ein Stück der gesamten Liste nehmen. Intern könnte das etwas bewirken, zum Beispiel eine Kopie des Listenobjekts erstellen, aber der Effekt sollte in diesem Fall derselbe sein.

+0

Hinweis: Da ich auf dieser Maschine keinen Zugriff auf Python habe, stütze ich mich auf die Ergebnisse von Skulptur, die als Ergebnis '0' ausgaben. Ich gehe davon aus, dass Skulptur (http://www.skulpt.org/) dasselbe tut, was CPython tun würde, was in diesem Eckfall nicht unbedingt eine sichere Annahme ist. –

1

Die for..in Struktur ist in der Python-Handbuch

http://docs.python.org/reference/compound_stmts.html#the-for-statement

beschrieben

Sie mehrere Variablen auf der linken Seite des in Stichwort

for [i,j] in [(1,2),(3,4),(5,6)]: 
    print i, j 

for [i,j] in [[1,2],[3,4],[5,6]]: 
    print i, j 

das Handbuch sagte, dass es haben kann interpretiert wie

i,j = (1,2) 

für die erste Iteration und so weiter. Daher können Sie eine leere Liste von Variablen haben, da die Liste, die iteriert wird, eine leere Liste als einziges Element hat. Diese Schleife wird einmalig 0 drucken.

Der Parser, den Sie gerade lesen, wurde er automatisch generiert? Diese Art von Anweisung kann von einer nicht-menschlichen Quelle erzeugt werden. Ich sehe seinen Zweck nicht.

+0

Der wichtige Teil ist das "Ziel" -Atom im Handbuch, das einen legalen Ausdruck auf der linken Seite definiert. –

1
for [] in [[]]: print 0 

bedeutet, dass für jede leere Iterables in [[]], dass eine Liste, die eine leere Liste enthält, drucken 0. Es ist nicht nur auf Listen beschränkt, sondern alle Iterables kann in die gestellt werden. Zum Beispiel können Sie versuchen:

# empty list, empty tuple, empty string, empty unicode 
for [] in [[],(), '', unicode()]: print 0 

und es würde 0 vier Mal drucken.

[] [:] ist genau wie []. Es wird eine leere Liste zurückgegeben, also ist meine Antwort die gleiche wie oben. sieht

0

Angenommen, Sie eine Liste von Tupeln, die wie folgt:

L = [(1,2), (3,4), (5,6)] 

Angenommen, Sie diese Tupel in besonderer Weise drucken möchten: explizit sein

for tup in L: 
    a = tup[0] 
    b = tup[1] 
    if a<b: 
     print a,b 
    else: 
     print b,a 

Aber die Zuordnung a und b Der Inhalt von tup ist ziemlich mühsam. So könnten Sie dies tun:

for tup in L: 
    a,b = tup 
    if a<b: 
     print a,b 
    else: 
     print b,a 

Aber man könnte es auch machen weniger langweilig:

for (a,b) in L: # you could also do "for [a,b] in L" 
    if a<b: 
     print a,b 
    else: 
     print b,a 

Hier (a,b) Muster passt gegen das Element, das durch die Iteration zurückgeführt wird. In der ersten Ausführung der for-Schleife, das Element durch Iteration zurückgegeben wird (1,2) ist, das Muster gegen (a,b) abgestimmt wird, die daher 1-a und 2-b

Jetzt in Ihrem ersten Beispiel weist, iterieren Sie über eine Liste mit einer leeren Liste. Dies bedeutet, dass Sie versuchen, so viele 0 s zu drucken, wie es [] s in dieser Liste gibt. Aber es ist ein wenig komplexer als das:

Wenn Sie versuchen, Muster wie in meinem dritten Beispiel, Python iteriert über die Liste (oder Tupel) von Variablen und das vom Iterator zurückgegebenen Element, gleichzeitig, die Zuweisung von Werten als sie gehen. Wenn Ihr Muster also keine Variablen enthält, sollte das Element, mit dem Sie ein Muster erstellen möchten, ebenfalls leer (und iterierbar) sein. Dies erklärt das folgende Verhalten:

>>> for i in 5: print i 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not iterable 

>>> for [] in [[], 5]: print 0 
... 
0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not iterable 

... und dieses Verhalten zu:

>>> x,y = (2,5,3) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 

>>> for [] in [[], [5]]: print 0 
... 
0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 

Jetzt, da für Ihr zweites Beispiel des [:] Betrieb schafft im Grunde eine Kopie der Liste Es wird aufgerufen, so dass die Änderung der ursprünglichen Liste die Kopie nicht verändert und umgekehrt:

So

, wenn Sie anrufen [][:], alles, was Sie tun, ist eine neue, leere Liste zu machen, die die gleichen wie meine Erklärung für Ihr erstes Beispiel