index - python for array
Python extraño comportamiento con enumerar (6)
De hecho: su primer fragmento de código modifica la lista de iteraciones en su lugar; el segundo señala la variable x
a una nueva lista, dejando la lista sin modificar transversalmente por enumerate()
. Puede ver esto en acción en los siguientes enlaces en www.pythontutor.com, que le permiten realizar un solo paso sobre su código y visualizar el contenido de sus variables:
Primera versión (
x
se modifica en su lugar).Segunda versión (
x
se redirige a[1]
).
Para ver mejor lo que está pasando, vaya here para pasar por encima del siguiente código ampliado:
x = [1,2,3,4,5]
view = enumerate(x)
for i, s in view:
x = [1]
print(i, s, x)
Sé que no debo modificar la lista dentro de un bucle, pero solo por curiosidad, me gustaría saber por qué el número de iteraciones es diferente entre los dos ejemplos siguientes.
Ejemplo 1:
x = [1, 2, 3, 4, 5]
for i, s in enumerate(x):
del x[0]
print(i, s, x)
Ejemplo 2:
x = [1,2,3,4,5]
for i, s in enumerate(x):
x = [1]
print(i, s, x)
El ejemplo 1 se ejecuta solo 3 veces porque cuando i==3
, len(x)==2
.
El ejemplo 2 se ejecuta 5 veces aunque len(x)==1
.
Entonces, mi pregunta es, ¿ enumerate
genera una lista completa de pares (index, value)
al comienzo del bucle y lo itera? ¿O se generan en cada iteración del bucle?
En el primer ejemplo, en realidad estás modificando la lista sobre la que estás iterando.
Por otro lado, en el segundo caso, solo estás asignando un nuevo objeto al nombre x
. Sin embargo, el objeto sobre el que recorre el bucle no cambia.
Eche un vistazo a http://foobarnbaz.com/2012/07/08/understanding-python-variables/ para obtener una explicación más detallada sobre los nombres y las variables en Python.
Otros ya han señalado que su segundo ejemplo solo cambia el valor al que x
puntos, pero no la lista sobre la que está iterando. Este es un ejemplo perfecto para la diferencia entre la asignación ordinaria ( x = [1]
) y la asignación de segmento ( x[:] = [1]
). El último modifica la lista de puntos x
a in situ :
x = [1, 2, 3, 4, 5]
for i, s in enumerate(x):
x[:] = [1]
print(i, s, x)
imprimirá
(0, 1, [1])
Solo una aclaración de lo que han dicho Wasi Ahmad y Wisperwind. Ambos afirman que "solo estás asignando un nuevo objeto al nombre x". Esto podría ser un poco confuso ya que podría interpretarse como que dice "estás creando un nuevo objeto ( [1]
) y almacenándolo con el nombre x
, al que dirías" Bueno, sí, ¿por qué no cambia? ? "Para ver lo que está sucediendo, imprima la identificación del objeto
x = [1, 2, 3, 4, 5]
y = x # To keep a reference to the original list
print id(x), id(y)
for i, v in enumerate(x):
x = [1]
print id(x), id(y)
print id(x), id(y)
# output (somewhat contrived as I don''t have a python environment set up)
# X ID Y ID
10000000000001 10000000000001
10000000000002 10000000000001
10000000000003 10000000000001
10000000000004 10000000000001
10000000000005 10000000000001
10000000000006 10000000000001
10000000000006 10000000000001
Notará que la id
de x
cambia cada vez que pasa por el bucle y cuando haya terminado con el bucle, x
apuntará a la última modificación realizada en el bucle. Cuando está pasando por su bucle, está iterando sobre la instancia original de x, independientemente de si aún puede hacer referencia a él.
Como puedes ver, y
apunta a la x
original. A medida que realiza sus iteraciones a través del bucle, a pesar de que x
está cambiando, y
sigue apuntando a la x
original que aún está en bucle.
enumerate() devuelve un iterador, o algún otro objeto que admita la iteración. El __next__() del iterador devuelto por enumerate() devuelve una tupla que contiene un recuento (desde el inicio, que por defecto es 0) y los valores obtenidos de la iteración sobre iterable .
__next__() devuelve el siguiente elemento del contenedor. Si no hay más elementos, levante la excepción StopIteration
.
¿Enumera () genera una lista completa de pares (índice, valor) al comienzo del bucle y se itera a través de él? ¿O se generan en cada iteración del bucle?
Entonces, enumerate()
devuelve un iterador y en cada iteración, __next__()
verifica si hay más elementos. enumerate()
no crea una lista completa al principio del bucle.
Como mencionó @Wisperwind , en su segundo caso, está asignando un nuevo objeto al nombre x
. El objeto, el bucle sobre el que se itera no cambia durante la iteración.
x = [1, 2, 3, 4, 5]
La lista [1, 2, 3, 4, 5]
está ''etiquetada'' con x
for i, s in enumerate(x):
enumerate () adjunta otra etiqueta, por lo que [1, 2, 3, 4, 5]
ahora está etiquetado como x
e y
. enumerate () continuará usando la etiqueta y
, no la etiqueta x
.
del x[0]
La lista almacenada en la memoria se modifica, por lo que tanto x
como y
ahora se refieren a [2, 3, 4, 5]
Alternativamente, cuando usas
x = [1]
Se crea una nueva lista [1]
en la memoria, y la etiqueta x
ahora apunta a eso. La etiqueta y
sigue apuntando a la lista original.
Cómo funciona la variable Python:
http://foobarnbaz.com/2012/07/08/understanding-python-variables/