Esta es más una cuestión conceptual. Recientemente vi un fragmento de código en Python (funcionó en 2.7, y también podría haberse ejecutado en 2.5) en el que un forbucle usaba el mismo nombre tanto para la lista que se estaba iterando como para el elemento en la lista , lo que me parece una mala práctica y algo que no debería funcionar en absoluto.
Por ejemplo:
x = [1,2,3,4,5]
for x in x:
print x
print x
Rendimientos:
1
2
3
4
5
5
Ahora, tiene sentido para mí que el último valor impreso sería el último valor asignado ax desde el ciclo, pero no entiendo por qué podría usar el mismo nombre de variable para ambas partes del forciclo y tener Funciona según lo previsto. ¿Están en diferentes ámbitos? ¿Qué está pasando debajo del capó que permite que algo como esto funcione?

for i in printAndReturn [1,2,3,4,5] …, ¿cuántas veces se deben[1,2,3,4,5]imprimir?forbucle tienen el mismo alcance.for ($x as $x)pero es un código feo IMORespuestas:
Que
disnos dice:Python 3.4.1 (default, May 19 2014, 13:10:29) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from dis import dis >>> dis("""x = [1,2,3,4,5] ... for x in x: ... print(x) ... print(x)""") 1 0 LOAD_CONST 0 (1) 3 LOAD_CONST 1 (2) 6 LOAD_CONST 2 (3) 9 LOAD_CONST 3 (4) 12 LOAD_CONST 4 (5) 15 BUILD_LIST 5 18 STORE_NAME 0 (x) 2 21 SETUP_LOOP 24 (to 48) 24 LOAD_NAME 0 (x) 27 GET_ITER >> 28 FOR_ITER 16 (to 47) 31 STORE_NAME 0 (x) 3 34 LOAD_NAME 1 (print) 37 LOAD_NAME 0 (x) 40 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 43 POP_TOP 44 JUMP_ABSOLUTE 28 >> 47 POP_BLOCK 4 >> 48 LOAD_NAME 1 (print) 51 LOAD_NAME 0 (x) 54 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 57 POP_TOP 58 LOAD_CONST 5 (None) 61 RETURN_VALUELos bits clave son las secciones 2 y 3: cargamos el valor de
x(24 LOAD_NAME 0 (x)) y luego obtenemos su iterador (27 GET_ITER) y comenzamos a iterar sobre él (28 FOR_ITER). Python nunca vuelve a cargar el iterador nuevamente .Aparte: no tendría ningún sentido hacerlo, ya que ya tiene el iterador, y como señala Abhijit en su respuesta , la Sección 7.3 de la especificación de Python realmente requiere este comportamiento).
Cuando el nombre
xse sobrescribe para apuntar a cada valor dentro de la lista anteriormente conocida comoxPython no tiene problemas para encontrar el iterador porque nunca necesita mirar el nombrexnuevamente para finalizar el protocolo de iteración.fuente
Usando su código de ejemplo como referencia principal
x = [1,2,3,4,5] for x in x: print x print xMe gustaría que hiciera referencia a la sección 7.3. La declaración for en el manual
Extracto 1
Lo que significa es que su variable
x, que es un nombre simbólico de un objetolist:[1,2,3,4,5]se evalúa como un objeto iterable. Incluso si la variable, la referencia simbólica cambia su lealtad, ya que la lista de expresiones no se evalúa nuevamente, no hay impacto en el objeto iterable que ya ha sido evaluado y generado.Nota
Extracto 2
Aquí, la suite se refiere al iterador y no a la lista de expresiones. Entonces, para cada iteración, el iterador se ejecuta para producir el siguiente elemento en lugar de referirse a la lista de expresiones original.
fuente
Es necesario que funcione de esta manera, si lo piensa. La expresión de la secuencia de un
forbucle podría ser cualquier cosa:binaryfile = open("file", "rb") for byte in binaryfile.read(5): ...No podemos consultar la secuencia en cada paso a través del ciclo, o aquí terminaríamos leyendo del siguiente lote de 5 bytes la segunda vez. Naturalmente, Python debe almacenar de alguna manera el resultado de la expresión de forma privada antes de que comience el ciclo.
No. Para confirmar esto, puede mantener una referencia al diccionario de alcance original ( locals () ) y notar que, de hecho, está usando las mismas variables dentro del ciclo:
x = [1,2,3,4,5] loc = locals() for x in x: print locals() is loc # True print loc["x"] # 1 breakSean Vieira mostró exactamente lo que está sucediendo bajo el capó, pero para describirlo en un código Python más legible, su
forciclo es esencialmente equivalente a estewhileciclo:it = iter(x) while True: try: x = it.next() except StopIteration: break print xEsto es diferente del enfoque tradicional de indexación para la iteración que vería en versiones anteriores de Java, por ejemplo:
for (int index = 0; index < x.length; index++) { x = x[index]; ... }Este enfoque fallaría cuando la variable de elemento y la variable de secuencia son iguales, porque la secuencia
xya no estaría disponible para buscar el índice siguiente después de que la primera vezxse reasigne al primer elemento.Sin embargo, con el primer enfoque, la primera línea (
it = iter(x)) solicita un objeto iterador que es realmente responsable de proporcionar el siguiente elemento a partir de ese momento.xYa no es necesario acceder directamente a la secuencia a la que apuntaba originalmente.fuente
Es la diferencia entre una variable (x) y el objeto al que apunta (la lista). Cuando comienza el ciclo for, Python toma una referencia interna al objeto al que apunta x. Utiliza el objeto y no lo que x hace referencia en un momento dado.
Si reasigna x, el ciclo for no cambia. Si x apunta a un objeto mutable (p. Ej., Una lista) y usted cambia ese objeto (p. Ej., Elimina un elemento), los resultados pueden ser impredecibles.
fuente
Básicamente, el ciclo for toma la lista
xy luego, almacenándola como una variable temporal, vuelve a asignarxa cada valor en esa variable temporal. Por lo tanto,xahora es el último valor de la lista.>>> x = [1, 2, 3] >>> [x for x in x] [1, 2, 3] >>> x 3 >>>Como en esto:
>>> def foo(bar): ... return bar ... >>> x = [1, 2, 3] >>> for x in foo(x): ... print x ... 1 2 3 >>>En este ejemplo,
xse almacenafoo()comobar, por lo que, aunquexse está reasignando, todavía existe (ed) enfoo()para que podamos usarlo para activar nuestroforbucle.fuente
xesté siendo reasignado. Sebarcrea una variable localfooy se le asigna el valor dex.fooluego devuelve ese valor en forma de un objeto que se usa en laforcondición. Por tanto, la variablexnunca se reasignó en el segundo ejemplo. Aunque estoy de acuerdo con el primero.xembargo, @Tonio sigue siendo la variable de iteración y, por lo tanto, toma un nuevo valor para cada ciclo. Después del bucle,xes igual a3en ambos casos.xmantenga3ynot[1,2,3] `?xya no se refiere a laxlista original , por lo que no hay confusión. Básicamente, Python recuerda que está iterando sobre laxlista original , pero tan pronto como comienzas a asignar el valor de iteración (0,1,2, etc.) al nombrex, ya no se refiere a laxlista original . El nombre se reasigna al valor de iteración.In [1]: x = range(5) In [2]: x Out[2]: [0, 1, 2, 3, 4] In [3]: id(x) Out[3]: 4371091680 In [4]: for x in x: ...: print id(x), x ...: 140470424504688 0 140470424504664 1 140470424504640 2 140470424504616 3 140470424504592 4 In [5]: id(x) Out[5]: 140470424504592fuente
xsimplemente deja de referirse a la lista de rangos y en su lugar se le asignan los nuevos valores de iteración. La lista de rangos todavía existe intacta. Si observa el valor dexafter the loop, será4xnunca se mencionax;xreferido a una secuencia. Luego se refirió1, luego a2, etc.