2015-11-05 2 views
5

Recentemente ho fatto 2 esperimenti:Perché il valore in dict è stato modificato in python?

(1):

>>> a = dict(zip([1,2,3],[4]*3)) 
>>> a 
{1: 4, 2: 4, 3: 4} 

>>> a[1] = 111  
>>> a 
{1: 111, 2: 4, 3: 4} 

(2):

>>> a = dict(zip([1,2,3],[{'a':True,'b':True}]*3)) 
>>> a 
{1: {'a': True, 'b': True}, 
2: {'a': True, 'b': True}, 
3: {'a': True, 'b': True}} 

>>> a[1]['a']=False # Here I changed the value of a[1]['a'] from True to False  
>>> a 
{1: {'a': False, 'b': True}, 
2: {'a': False, 'b': True}, 
3: {'a': False, 'b': True}}  #all 'a' value changed to False. 

Perché questo problema in (2) si è verificato? E perché (1) non hanno questo problema?

risposta

7

Risposta breve: perché gli oggetti dict sono modificabili e gli oggetti int sono immutabili.

Dettagli:

sguardo al [{'a': True, 'b': True}] * 3

Con

>>> l = [{}] * 3 

si crea lista che contiene riferimento allo stesso oggetto per 3 volte.

>>> id(l[0]) 
139685186829320 
>>> id(l[1]) 
139685186829320 
>>> id(l[2]) 
139685186829320 

Quindi, quando si cambia uno di loro, li cambia tutto (in caso di oggetti mutabili).

Se volete elenco dei diversi dizionari, è possibile farlo con:

>>> l = [{} for x in range(3)] 
>>> id(l[0]) 
139685161766216 
>>> id(l[1]) 
139685161766536 
>>> id(l[2]) 
139685161766600 

Nel tuo caso dovrebbe assomigliare a questa:

a = dict(zip([1, 2, 3], [{'a': True, 'b': True} for i in range(3)])) 

Con oggetti immutabili è diverso.

Non è possibile modificare l'oggetto immutabile. Ovunque, dove sembra che tu abbia cambiato un oggetto immutabile, viene invece creato un nuovo oggetto.

Così, quando si tenta di cambiamento oggetto immutabile elenco all'interno, viene creato un nuovo oggetto:

>>> l = [1] * 3 

>>> id(l[0]) 
139685185487008 
>>> id(l[1]) 
139685185487008 
>>> id(l[2]) 
139685185487008 

>>> l[0] = 2 

>>> id(l[0]) 
139685185487040 # new object created instead of old object being modified 
>>> id(l[1]) 
139685185487008 
>>> id(l[2]) 
139685185487008 
0

Se si utilizza di lista (sostituzione per zip) o per() ciclo che non sarà utilizzare lo stesso oggetto 3 volte

a = {ctr:{'a':True,'b':True} for ctr in range(1, 4)} 
print a 
a[1]['a']=False 
print a