2012-09-30 21 views
14

Sto scrivendo un parser, e nel processo di debug, ho scoperto che a quanto pare, questo è Python legale:Che cosa significa questa istruzione Python?

for [] in [[]]: print 0 

e così è questo (!):

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

I non incolpare il parser per essere confuso ... Sono avendo problemi a capire come interpretarlo!

Che cosa significa esattamente questa affermazione?

+0

google per la sequenza disimballaggio. Dovrebbe spiegarlo. – hendrik

risposta

14

In termini di esecuzione: nulla.

Il ciclo for si scorre su una lista vuota, quindi non si verificheranno iterazioni.

E questa è una buona cosa, perché il for [] significa: assegnare ciascuna voce nel ciclo a 0 variabili. L'ultima parte è probabilmente ciò che ti sta sconcertando.

L'istruzione è legale perché lo target token token_list consente di assegnare i valori di una sequenza a una sequenza di nomi di variabili ugualmente grande; chiamiamo questa tupla decompressione. I seguenti sono esempi più utili di liste target, in assegnazione e la cancellazione:

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

Si può fare lo stesso in un ciclo for:

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

È possibile utilizzare entrambi tuple e liste per la target_list Token , anche questo è legale:

[a, b] = (1, 2) 

Tuttavia, in Python, una lista può essere vuota. Così, il seguente è legale, ma non chiacchiere:

[] = [] 

e, infine, è quindi questo:

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

Più divertimento con le liste di destinatari:

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

Ora la sinistra lato mano sta usando una fetta nel compito. Dalla documentazione:

Se la destinazione è una divisione: viene valutata l'espressione primaria nel riferimento. Dovrebbe produrre un oggetto di sequenza mutabile (come una lista). L'oggetto assegnato dovrebbe essere un oggetto sequenza dello stesso tipo. Successivamente, le espressioni di limite inferiore e superiore vengono valutate, nella misura in cui sono presenti; i valori di default sono zero e la lunghezza della sequenza. I limiti dovrebbero valutare in (piccoli) numeri interi. Se uno dei due vincoli è negativo, viene aggiunta la lunghezza della sequenza. I limiti risultanti vengono ritagliati tra 0 e la lunghezza della sequenza, inclusi. Infine, viene chiesto all'oggetto sequenza di sostituire la sezione con gli elementi della sequenza assegnata. La lunghezza della sezione può essere diversa dalla lunghezza della sequenza assegnata, modificando quindi la lunghezza della sequenza di destinazione, se l'oggetto lo consente.

Quindi qui non si utilizza più il disimballaggio della tupla; sostituiamo invece una sezione della lista di sinistra con la lista di destra. Ma poiché nel nostro esempio l'elenco a sinistra è un letterale anonimo, l'elenco alterato risultante viene perso di nuovo.

Ma perché un tale assegnazione è anche legale in un ciclo for, il seguente è la sintassi legale, anche se piuttosto non chiacchiere:

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

Ah, questo spiega perché 'per [] in [[]]: stampa 0' funziona, ma che dire' per [] [:] in [[]]: stampa 0'? Come è legale/cosa significa? – Mehrdad

+2

L'elenco non è vuoto. Contiene un elemento, che è la lista vuota. Pertanto, 0 verrà stampato. –

+0

@Mehrdad: il 'target_list' sul lato sinistro può essere un assegnamento di slice. 'alist [1: 2]' = somelist' sostituisce la porzione indicata da '[1: 2]' dai valori di 'somelist'. Quindi una porzione è un'espressione valida sul lato sinistro per un compito, e anche questo è valido in un ciclo. –

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

è equivalente a:

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 

ma il primo si aspetta che il valore non venga restituito dall'elenco, i, e, i valori all'interno dell'elenco siano vuoti o il loro len() i s 0.

Non è possibile utilizzare () perché non è valido.

perché in python, è possibile ALSS assegnare in questo modo:

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

Ecco la mia ipotesi migliore:

for [] in [[]] mezzi "per ogni istanza di [] (un elenco di oggetti vuoto) in questo elenco [[]] (un elenco con esattamente un elemento, che è un oggetto elenco vuoto), print 0.

Nel secondo caso, penso chechiamerà solo slice() w con tutti i valori predefiniti, che prenderanno semplicemente una porzione dell'intera lista. Internamente ciò potrebbe fare qualcosa, ad esempio fare una copia dell'oggetto lista, ma l'effetto in questo caso dovrebbe essere lo stesso.

+0

Nota: poiché non ho accesso a Python su questa macchina, sto basando questa ipotesi sui risultati di Skulpt, che ha stampato '0' come risultato. Suppongo che Skulpt (http://www.skulpt.org/) stia facendo la stessa cosa che CPython farebbe, il che non è necessariamente un presupposto sicuro in questo caso d'angolo. –

1

La struttura for..in è descritta nel manuale di Python

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

Si possono avere più variabili a sinistra la parola in

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 

manuale ha detto che è interpretato come

i,j = (1,2) 

per la prima iterazione e così via. Pertanto, puoi avere una lista vuota di variabili poiché l'elenco iterato ha una lista vuota come unico elemento. Questo ciclo stamperà 0 una volta.

Il parser che stai leggendo è stato generato automaticamente? Questo tipo di affermazione può essere generata da una fonte non umana. Non vedo lo scopo.

+0

La parte importante è l'atomo "target" nel manuale, che definisce un'espressione legale del sito sinistro. –

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

significa che per ogni iterables vuoti nel [[]], che è una lista che contiene una lista vuota, stampa 0. Non è solo limitato ad elenchi, ma ogni iterables può essere messo in questo. Ad esempio, puoi provare:

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

e stampa quattro volte.

[] [:] è uguale a []. Restituirà una lista vuota, quindi la mia risposta è la stessa di sopra.

0

Si supponga di avere una lista di tuple che assomiglia a questo:

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

Si supponga di voler stampare questi tuple in qualche modo speciale:

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

Ma assegnando lo a e b esplicitamente di essere il contenuto di tup è piuttosto noioso. Così si potrebbe fare questo:

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

Ma si potrebbe rendere ancora meno noioso:

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

Qui, (a,b) modello corrisponde contro l'elemento che viene restituito dalla iterazione. Nella prima esecuzione del ciclo for, l'elemento viene restituito per iterazione è (1,2), che ottiene modello confrontato (a,b), che assegna quindi 1-a e 2-b

Ora, nel primo esempio, si effettua l'iterazione una lista contenente una lista vuota. Ciò significa che stai tentando di stampare tutti gli 0 s in quanto ci sono [] s in questo elenco. Ma è un po 'più complesso di quello:

Quando si tenta di eseguire lo schema come nel mio terzo esempio, python esegue iterazioni sull'elenco (o tupla) di variabili e l'elemento restituito dall'iteratore, assegnando simultaneamente i valori mentre partire. Quindi, quando il tuo pattern non contiene variabili, anche l'elemento con cui stai cercando pattern match dovrebbe essere vuoto (e iterabile). Questo spiega il seguente comportamento:

>>> 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 

... e questo comportamento troppo:

>>> 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 

Ora, come per il secondo esempio, l'operazione [:] crea sostanzialmente una copia della lista viene chiamato, in modo che la modifica dell'elenco originale non altera la copia e viceversa:

>>> L = [1,2,3] 
>>> M = L 
>>> M[0] = 'a' 
>>> print L[0] 
'a' 

>>> L = [1,2,3] 
>>> M = L[:] 
>>> M[0] = 'a' 
>>> print L[0] 
1 

Quindi, quando si chiamano [][:], tutto quello che stai facendo sta facendo un nuovo elenco vuoto, che funziona allo stesso modo la mia spiegazione per il primo esempio

Problemi correlati