5

I am seeing some unusual behavior in Python dictionary:

import numpy as np
td =[np.Inf, 2, 3]
a = {}
# First initialize contents of dictionary to a list of values
for k in range(10):
    a[k] = td

# now I want to access the contents to modify them based on certain criteria 
for k in range(10):
    c = a[k]
    c[0] = k
    a[k] = c

From this I would expect each first item of the list for each dictionary key value to be changed based on (c[0] = k), however, what I get at the end is that all values of the dictionary are updated to the last value of k, as in:

{0: [9, 2, 3], 1: [9, 2, 3], 2: [9, 2, 3], 3: [9, 2, 3], 
 4: [9, 2, 3], 5: [9, 2, 3], 6: [9, 2, 3], 7: [9, 2, 3], 
 8: [9, 2, 3], 9: [9, 2, 3]}

Am I missing something, or there is something wrong in the dictionary definition?

I can work around this in a different way for my code to run, but I am interested as to why the dictionary class would behave this way.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Nader
  • 660
  • 1
  • 11
  • 17

3 Answers3

11

Because each key gets the same list... To make a shallow copy of the list, use the following syntax:

for k in range(10):
    a[k] = td[:] 

Demo:

>>> d = {}
>>> el = [1, 2, 3]
>>> d[0] = el
>>> d[1] = el
>>> map(id, d.values())
[28358416, 28358416]
MrTux
  • 32,350
  • 30
  • 109
  • 146
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
  • Thanks, My impression was that the value of (td) would be reinitialized every time, i.e, old value destroyed, with each new assignment, however, I know now that the dictionary behaves differently. :) – Nader Nov 21 '12 at 17:23
  • @Nader it's not the dictionary.... If you did `mylist = []; for i in range(10): mylist.append(el)` you'd have the same thing :) – Jon Clements Nov 21 '12 at 17:24
  • I understand that, however, I would expect that if I change the value of (el) inside the loop, then the appended value would change accordingly (e.g. mylist = []; for i in range(10): el=i; mylist.append(el)), which in this case it does, but not for dictionary. – Nader Nov 21 '12 at 17:35
2

This is happening because when you insert the value into the dict, you are not inserting a brand new list. You are actually inserting a reference to the same old list. So when you change one value, you are actually changing the list that the value points to, and therefore the list that all values point to.

If you really want separate lists for each value, then you'd be better off making a shallow copy of the list at insertion time like so:

td =[np.Inf, 2, 3]
for k in range(10):
    a[k] = td[:] #making a new list out of the old one

Now, this will work the way you expect

for k in range(10):
    c = a[k]
    c[0] = k
    a[k] = c

Hope this helps

inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
0

When you reference td in the line a[k] = td, you're actually appending a reference to the original list. Any modification of that list is visible wherever it's referenced. You need to use the copy module in order to make a new list (or build a new list for each entry, in the loop itself):

for k in range(10):
    a[k] = [np.Inf, 2, 3]
asthasr
  • 9,125
  • 1
  • 29
  • 43