4

I am trying to create a dict of lists that can be appended to in a for loop. However, if I create a dict using fromkeys, the list becomes a copy of a "pointer", not a new list. For example,

newdict = dict.fromkeys(range(10), [])

-- or --

newdict = dict.fromkeys(range(10), list())

both yield the same data structure, a dict with the SAME list as the value pair. So that when any key is updated e.g. - newdict[0].append(100), the corresponding output of print newdict is:

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

Any thoughts on how to avoid this without having to iterate through in a for loop? Thanks in advance.

paulski
  • 318
  • 1
  • 7
  • 3
    Minor: you mean `newdict[0].append(100)`, or `newdict[0] += [100]`, not `newdict[0] = 100`. – DSM Dec 21 '13 at 04:47
  • I'm not getting this behavior with 3.3.3: `newdict[0]=100` yields `{0: 100, 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: []}`... – MattDMo Dec 21 '13 at 04:47

4 Answers4

5

The two most common approaches are to use a dict comprehension:

>>> d = {k: [] for k in range(10)}
>>> d[3].append(100)
>>> d
{0: [], 1: [], 2: [], 3: [100], 4: [], 5: [], 6: [], 7: [], 8: [], 9: []}

Or to use a defaultdict and forego setting any keys at all:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d
defaultdict(<type 'list'>, {})
>>> d[9].append(100)
>>> d
defaultdict(<type 'list'>, {9: [100]})

As a third option, by using setdefault -- e.g. d.setdefault(k, []) instead of d[k], like in the defaultdict case, you can avoid needing to preset []:

>>> d = {}
>>> d.setdefault(3, []).append(100)
>>> d
{3: [100]}
DSM
  • 342,061
  • 65
  • 592
  • 494
4

Maybe a dict comprehension?

newdict = {x: [] for x in range(10)}
Xymostech
  • 9,710
  • 3
  • 34
  • 44
0

I think you want to do

newdict[0].append(100)

right?

James King
  • 6,229
  • 3
  • 25
  • 40
0

fromkeys is a static method of the dict class. The default behavior is designed to set a set of dictionary keys to a single value such as set a multi set counter:

>>> d={}.fromkeys('abc',0)
>>> d
{'a': 0, 'c': 0, 'b': 0}
>>> d['a']+=1
>>> d
{'a': 1, 'c': 0, 'b': 0}

You can patch it to call a function for each element:

>>> class FixFromKeys(dict):
...     def fromkeys(cls, seq, func):
...         return {key:func() for key in seq}
... 
>>> d=FixFromKeys().fromkeys([1,2,3],list)
>>> d[1].append(1)
>>> d
{1: [1], 2: [], 3: []}
dawg
  • 98,345
  • 23
  • 131
  • 206