5

Recently I have done 2 experiments:

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

Why this problem in (2) occurred? And why (1) haven't this problem?

Remi Guan
  • 21,506
  • 17
  • 64
  • 87
txmc
  • 271
  • 2
  • 8

2 Answers2

7

Short answer: because dict objects are mutable, and int objects are immutable.

Details:

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

With

>>> l = [{}] * 3

you create list which contains reference to the same object 3 times.

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

So when you change one of them, you change them all (in case of mutable objects).

If you want list of different dictionaries, you can do it with:

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

In your case it should look like this:

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

With immutable objects it is different.

You cannot change immutable object. Everywhere where it seems like you change immutable object, a new object is created instead.

So when you try to change immutable object inside list, a new object is created:

>>> 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
Mikhail M.
  • 5,588
  • 3
  • 23
  • 31
0

If you use list comprehension (replacement for zip) or a for() loop you won't be using the same object 3 times

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