2012-09-30 17 views
14

Estoy escribiendo un programa de análisis, y en el proceso de depuración, encontré que al parecer, esto es legal Python:¿Qué significa esta declaración de Python?

for [] in [[]]: print 0 

y así es esta (!):

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

I no culpe al analizador por confundirse ... ¡Tengo teniendo problemas para entender cómo interpretarlo!

¿Qué significa exactamente esta declaración?

+0

Google para la secuencia de desempacar. Debería explicarlo. – hendrik

Respuesta

14

En términos de ejecución: nada.

El bucle for recorre una lista vacía, por lo que no tendrá lugar ninguna iteración.

Y eso es bueno, porque el for [] significa: asignar cada entrada en el ciclo a 0 variables. La última parte es probablemente lo que te desconcierta.

La declaración es legal porque el target token token_list le permite asignar los valores en una secuencia a una secuencia igualmente grande de nombres de variables; llamamos a esta tupla desempacar. Los siguientes son ejemplos más útiles de listas de objetivos, en la asignación y la supresión:

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

puede hacer lo mismo en un bucle for:

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

Puede utilizar ambos tuplas y listas para el token target_list , esto también es legal:

[a, b] = (1, 2) 

Sin embargo, en Python, una lista puede estar vacía. Por lo tanto, la siguiente es legal, sin embargo sin sentido:

[] = [] 

y, por último, por lo que es la siguiente:

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

Más diversión con listas de objetivos:

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

Ahora la izquierda lado de la mano está usando una porción en la tarea. De la documentación:

Si el destino es un corte: se evalúa la expresión principal en la referencia. Debería producir un objeto de secuencia mutable (como una lista). El objeto asignado debe ser un objeto de secuencia del mismo tipo. A continuación, las expresiones límite inferior y superior se evalúan, en la medida en que están presentes; los valores por defecto son cero y la longitud de la secuencia. Los límites deben evaluarse en enteros (pequeños). Si cualquiera de los límites es negativo, se agrega la longitud de la secuencia. Los límites resultantes se recortan para estar entre cero y la longitud de la secuencia, inclusive. Finalmente, se le pide al objeto de secuencia que reemplace el corte con los elementos de la secuencia asignada. La longitud del corte puede ser diferente de la longitud de la secuencia asignada, cambiando así la longitud de la secuencia objetivo, si el objeto lo permite.

Así que aquí ya no estamos utilizando desempaquetado de tuplas; en su lugar, reemplazamos una sección de la lista de la izquierda con la lista de la derecha. Pero como en nuestro ejemplo la lista de la izquierda es una lista anónima literal, la lista alterada resultante se pierde de nuevo.

Pero debido a que una misión de este tipo también es legal en un bucle, la siguiente es la sintaxis legal, aunque bastante sin sentido:

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

Ah, eso explica por qué 'para [] en [[]]: imprimir 0' funciona, pero ¿qué pasa con' para [] [:] en [[]]: imprimir 0'? ¿Cómo es eso legal/qué significa? – Mehrdad

+2

La lista no está vacía. Contiene un elemento, que es la lista vacía. Por lo tanto, 0 se imprimirá. –

+0

@Mehrdad: el lado izquierdo 'target_list' puede ser una asignación de sector. 'alist [1: 2]' = somelist' reemplaza la porción indicada por '[1: 2]' por los valores de 'somelist'. Por lo tanto, un sector es una expresión válida del lado izquierdo de una tarea, y eso también es válido en un ciclo. –

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

es 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 

pero el primero espera que no se devuelva ningún valor de la lista, i, e los valores dentro de la lista están vacíos o su len() i s 0.

No puede usar () allí ya que no es válido.

porque en Python, puede asignar los alss así:

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

Aquí está mi mejor conjetura:

for [] in [[]] medios "para cada instancia de [] (una lista de objetos vacío) en esta lista [[]] (una lista con exactamente un elemento, que es un objeto de lista vacío), print 0.

En el segundo caso, creo que [:] simplemente llamará a slice() w con todos los valores predeterminados, que simplemente tomarán una porción de la lista completa. Internamente, eso podría hacer algo, por ejemplo hacer una copia del objeto de la lista, pero el efecto en este caso debería ser el mismo.

+0

Nota: Como no tengo acceso a Python en esta máquina, estoy basando esta suposición en los resultados de Skulpt, que imprimió '0' como resultado. Asumo que Skulpt (http://www.skulpt.org/) está haciendo lo mismo que CPython, lo cual no es necesariamente una suposición segura en este caso de esquina. –

1

La estructura for..in se describe en el manual de Python

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

Usted puede tener múltiples variables a la izquierda de la palabra clave 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 

el manual dice que es interpretado como

i,j = (1,2) 

para la primera iteración y así sucesivamente. Por lo tanto, puede tener una lista vacía de variables, ya que la lista iterada tiene una lista vacía como único elemento. Este ciclo imprimirá 0 una vez.

El analizador que está leyendo, ¿ha sido generado automáticamente? Este tipo de declaración puede ser generada por una fuente no humana. No veo su propósito.

+0

La parte importante es el átomo 'objetivo' en el manual, que define una expresión legal del lado izquierdo. –

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

significa que para cada iterables vacíos en [[]], que es una lista que contiene una lista vacía, imprimir 0. No es sólo limitado a las listas, pero cada iterables se puede poner en eso. Por ejemplo, puede intentar:

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

e imprimiría 0 cuatro veces.

[] [:] es lo mismo que []. Devolverá una lista vacía, por lo que mi respuesta es la misma que la anterior.

0

Suponga que tiene una lista de tuplas que tiene este aspecto:

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

Supongamos que desea imprimir estas tuplas de una forma especial:

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

Pero la asignación de a y b explícitamente como el contenido de tup es bastante tedioso. Así que es posible hacer esto:

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

Pero podría hacerlo aún menos tedioso:

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

Aquí, (a,b) patrón coincide con el elemento que se devuelve por la iteración. En la primera ejecución del bucle, el elemento que se devuelve por iteración es (1,2), que recibe el patrón emparejado contra (a,b), que por lo tanto asigna 1-a y 2-b

Ahora, en su primer ejemplo, que está interactuando sobre una lista que contiene una lista vacía. Esto significa que está intentando imprimir tantos 0 s como hay [] s en esta lista. Pero es un poco más complejo que eso:

Cuando intenta hacer coincidir patrones como en mi tercer ejemplo, python itera sobre la lista (o tupla) de variables y el elemento devuelto por el iterador, al mismo tiempo, asignando valores a medida que ir. Entonces, cuando su patrón no contiene variables, entonces el elemento con el que está tratando de emparejar el patrón también debe estar vacío (e iterable). Esto explica el siguiente comportamiento:

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

... y este comportamiento también:

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

Ahora, en cuanto a su segundo ejemplo, la operación [:], básicamente, crea una copia de la lista se invoca, de modo que alterar la lista original no altera la copia y 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 

Así que cuando se llama a [][:], todo lo que está haciendo es hacer una nueva lista vacía, que funciona igual que mi explicación para su primer ejemplo

Cuestiones relacionadas