2015-11-05 4 views
5

Ostatnio zrobiłem 2 eksperymenty:Dlaczego wartość w dyktaferze zmieniła się w sumie w pythonie?

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

dlaczego wystąpił ten problem (2)? I dlaczego (1) nie masz tego problemu?

Odpowiedz

7

Krótka odpowiedź: ponieważ dict obiekty są zmienne, a int obiekty są niezmienne.

Szczegóły:

Look w [{'a': True, 'b': True}] * 3

Z

>>> l = [{}] * 3 

Państwo listę, która zawiera odniesienie do tego samego obiektu 3 razy utworzyć.

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

Więc po zmianie jednego z nich, należy je wszystkie zmiany (w przypadku obiektów modyfikowalnych).

Jeśli chcesz listę różnych słowników, można zrobić to z:

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

W Twoim przypadku powinno to wyglądać tak:

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

Przy niezmiennych obiektów jest inny.

Nie można zmienić obiektu niezmiennego. Wszędzie tam, gdzie wydaje się, że zmieniasz niezmienny obiekt, tworzony jest nowy obiekt.

Więc podczas próby zmiany niezmienny obiekt listy wewnątrz, nowy obiekt jest tworzony:

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

Jeśli używasz listowych (wymiana na zamek) lub do() pętli nie będzie używać tego samego obiektu 3 razy

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