I came across this weird issue this morning:
>>> l = ['a', 'b', 'c']
>>> dict = dict.fromkeys(l, [])
>>> dict['a'] += [1]
>>> dict
{'a': [1], 'c': [1], 'b': [1]}
I can not explain why this happens?
I came across this weird issue this morning:
>>> l = ['a', 'b', 'c']
>>> dict = dict.fromkeys(l, [])
>>> dict['a'] += [1]
>>> dict
{'a': [1], 'c': [1], 'b': [1]}
I can not explain why this happens?
dict.fromkeys
creates a whole bunch of references to the same list. In other words, d['a']
is d['b']
etc. When you do +=
you extend the list in place, so modifications are seen in all the lists -- after all, they're the same list.
>>> l = ['a', 'b', 'c']
>>> d = dict.fromkeys(l, [])
>>> d
{'a': [], 'c': [], 'b': []}
>>> print [id(v) for v in d.values()] # Note, they all have the same ID -- They're the same.
[4385936016, 4385936016, 4385936016]
>>> d['a'] += [1]
>>> d
{'a': [1], 'c': [1], 'b': [1]}
As pointed out in the comments, I didn't actually tell you how to get around this problem. If you want to initialize a dictionary with keys that are instances of mutable values, you can use a dictionary comprehension:
d = {key: [] for key in l}
Or, if you're stuck with an old version of python (before python2.7), you pass an iterable that yields 2-tuples to the dict constructor:
d = dict((key, []) for key in l)
Note that there are other variants as well that are useful to know about (colections.defaultdict
, a regular dict subclass with overridden __missing__
). Each of these has slightly different behaviors that I explain here. However, this should be good enough to get you going for the time being...
You might be interested in a collections.defaultdict:
In [66]: d = collections.defaultdict(list)
In [67]: d['a'] += [1]
In [68]: d
Out[68]: defaultdict(<class 'list'>, {'a': [1]})
In [69]: dict(d)
Out[69]: {'a': [1]}
In [70]: d['b']
Out[70]: []
In [71]: dict(d)
Out[71]: {'b': [], 'a': [1]}
In [72]: d['c']
Out[72]: []
In [73]: dict(d)
Out[73]: {'b': [], 'c': [], 'a': [1]}