2010-05-28 17 views
6

Me pregunto sobre algunos detalles de cómo ... en trabajos en Python.¿Por qué el "para ... en" funciona de manera diferente en una lista de valores frente a una lista de diccionarios?

Mi comprensión es for var in iterable en cada iteración crea una variable, var, vinculada al valor actual de iterable. Entonces, si haces for c in cows; c = cows[whatever], pero cambiar c dentro del ciclo no afecta el valor original. Sin embargo, parece funcionar de manera diferente si está asignando un valor a una clave de diccionario.

cows=[0,1,2,3,4,5] 
for c in cows: 
    c+=2 

#cows is now the same - [0,1,2,3,4,5] 

cows=[{'cow':0},{'cow':1},{'cow':2},{'cow':3},{'cow':4},{'cow':5}] 
for c in cows: 
    c['cow']+=2 

# cows is now [{'cow': 2}, {'cow': 3}, {'cow': 4}, {'cow': 5}, {'cow': 6}, {'cow': 7} 
#so, it's changed the original, unlike the previous example 

veo uno puede utilizar enumeración de hacer el primer trabajo ejemplo, también, pero eso es una historia diferente, supongo.

cows=[0,1,2,3,4,5] 
for i,c in enumerate(cows): 
    cows[i]+=1 

# cows is now [1, 2, 3, 4, 5, 6] 

¿Por qué afecta los valores de la lista original en el segundo ejemplo, pero no el primero?

[editar]

Gracias por las respuestas. Estaba viendo esto desde un punto de vista PHP, donde puede usar el símbolo & en foreach para especificar si está operando en una referencia o una copia del iterable. Ahora veo que la diferencia real es un detalle básico de cómo funciona Python con respecto a los objetos inmutables.

Respuesta

4

No tiene nada que ver con for ... in .... Cambie su código de for c in cows: a c = cows[3] (y defina la siguiente línea) en cada ejemplo y vea el efecto.

En su primer ejemplo, los elementos de la lista son objetos int; ellos son inmutables En el segundo ejemplo, son objetos dict, que son mutables.

+0

Acepté su respuesta porque 'inmutable' es la palabra mágica. Recuerdo ahora que los enteros son objetos separados en Python, por lo que se volvió a vincular ese nombre a otro objeto en el primer ejemplo y se modificó el mismo objeto en el segundo. – JAL

3

Hacer una asignación de nombre como lo ha hecho en el primer ciclo solo vuelve a enlazar el nombre. Hacer una asignación de artículo como lo ha hecho en el segundo ciclo modifica el objeto existente.

4

c es una variable temporal, desechable en ambos casos. (Tenga en cuenta que en Python, todas las variables son simplemente referencias, vinculadas a los objetos que representan y capaces de rebotar en diferentes objetos. Python es más consistente que ciertos otros idiomas a este respecto.)

En su lista ejemplo , cada iteración vuelve a enlazar c de un entero a otro, sin modificar la lista original.

En su ejemplo de dict, cada iteración accede al dict al cual c está temporalmente vinculado, y vuelve a vincular uno de los miembros de ese dict a un número entero diferente.

En ambos casos, c se ignora al final del ciclo, pero como ha cambiado una estructura de datos que no es c en el segundo caso, observa los cambios cuando finaliza el ciclo.

5

En realidad, no está actuando de manera diferente. Cambiar una variable no es lo mismo que cambiar el atributo de una variable. Usted verá lo mismo en el siguiente ejemplo:

a = 1 
b = a 
b = 2 

Aquí a es fija 1. b se le asignó un valor diferente y ya no es lo mismo que un

a = {"hello": 1} 
b = a 
b["hello"] = 2 

Aquí vuelve a["hello] 2 en lugar de 1. b sigue siendo el mismo valor porque no asignamos nada a b, y por lo tanto b es lo mismo que a.Cambiamos la propiedad ["hello"] de b a 2 y desde a y b son la misma variable a["hello"] es también 2

16

Ayuda a imaginar lo que ocurre con la referencia de que c en cada iteración:

[ 0, 1, 2, 3, 4, 5 ] 
^
    | 
    c 

c contiene una referencia que apunta al primer elemento en la lista. Cuando lo haga c += 2 (es decir, c = c + 2, la variable temporal c se reasigna un nuevo valor. Este nuevo valor es 2 y c es de rebote a este nuevo valor. La lista original se queda solo.

[ 0, 1, 2, 3, 4, 5 ] 

    c -> 2 

Ahora, en el caso de diccionario, esto es lo que está obligado a c durante la primera iteración:.

[ {'cow':0}, {'cow':1}, {'cow':2}, {'cow':3}, {'cow':4}, {'cow':5} ] 
    ^
    | 
    c 

aquí, c apunta al objeto de diccionario {'cow':0} al hacer c['cow'] += 2 (es decir, c['cow'] = c['cow'] + 2), el objeto del diccionario mismo se cambia, ya que c no se recupera a un objeto no relacionado. Es decir, c aún apunta a ese primer objeto de diccionario.

[ {'cow':2}, {'cow':1}, {'cow':2}, {'cow':3}, {'cow':4}, {'cow':5} ] 
    ^
    | 
    c 
+0

+1, muy, muy buena respuesta! :) – jathanism

+0

+1 para la representación pictoral – Davy8

1

En el segundo ejemplo, usted tiene una lista de objetos diccionario. c hace referencia al objeto de diccionario que se modifica dentro del alcance del bucle.

1

Independientemente de bucle, que tiene que observar que:

some_var = some_object 

une el nombre some_var al objeto some_object. El objeto anterior (si lo hubiera) al que hace referencia el some_var está desatado.

some_var[some_index] = some_object 

no se une/unbind some_var; que es el azúcar solo sintáctica para lo siguiente:

some_var.__setitem__(some_index, some_object) 

Obviamente, some_var todavía señala a la misma indexable (una secuencia o un mapeo) de objeto como antes, que acaba de ser modificado.

Cuestiones relacionadas