dict.fromkeys all point to same list

Posted on

Solving problem is about exposing yourself to as many situations as possible like dict.fromkeys all point to same list and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about dict.fromkeys all point to same list, which can be followed any time. Take easy to follow this discuss.

dict.fromkeys all point to same list

This was causing me a bit of grief…

I created a dictionary from a list

l = ['a','b','c']
d = dict.fromkeys(l, [0,0]) # initializing dictionary with [0,0] as values
d['a'] is d['b'] # returns True

How can I make each value of the dictionary a seperate list? Is this possible without iterating over all keys and setting them equal to a list? I’d like to modify one list without changing all the others.

Answer #1:

You could use a dict comprehension:

>>> keys = ['a','b','c']
>>> value = [0, 0]
>>> {key: list(value) for key in keys}
    {'a': [0, 0], 'b': [0, 0], 'c': [0, 0]}
Answered By: Blender

Answer #2:

This answer is here to explain this behavior to anyone flummoxed by the results they get of trying to instantiate a dict with fromkeys() with a mutable default value in that dict.

Consider:

#Python 3.4.3 (default, Nov 17 2016, 01:08:31) 
# start by validating that different variables pointing to an
# empty mutable are indeed different references.
>>> l1 = []
>>> l2 = []
>>> id(l1)
140150323815176
>>> id(l2)
140150324024968

so any change to l1 will not affect l2 and vice versa.
this would be true for any mutable so far, including a dict.

# create a new dict from an iterable of keys
>>> dict1 = dict.fromkeys(['a', 'b', 'c'], [])
>>> dict1
{'c': [], 'b': [], 'a': []}

this can be a handy function.
here we are assigning to each key a default value which also happens to be an empty list.

# the dict has its own id.
>>> id(dict1)
140150327601160
# but look at the ids of the values.
>>> id(dict1['a'])
140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

Indeed they are all using the same ref!
A change to one is a change to all, since they are in fact the same object!

>>> dict1['a'].append('apples')
>>> dict1
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}
>>> id(dict1['a'])
>>> 140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

for many, this was not what was intended!

Now let’s try it with making an explicit copy of the list being used as a the default value.

>>> empty_list = []
>>> id(empty_list)
140150324169864

and now create a dict with a copy of empty_list.

>>> dict2 = dict.fromkeys(['a', 'b', 'c'], empty_list[:])
>>> id(dict2)
140150323831432
>>> id(dict2['a'])
140150327184328
>>> id(dict2['b'])
140150327184328
>>> id(dict2['c'])
140150327184328
>>> dict2['a'].append('apples')
>>> dict2
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}

Still no joy!
I hear someone shout, it’s because I used an empty list!

>>> not_empty_list = [0]
>>> dict3 = dict.fromkeys(['a', 'b', 'c'], not_empty_list[:])
>>> dict3
{'c': [0], 'b': [0], 'a': [0]}
>>> dict3['a'].append('apples')
>>> dict3
{'c': [0, 'apples'], 'b': [0, 'apples'], 'a': [0, 'apples']}

The default behavior of fromkeys() is to assign None to the value.

>>> dict4 = dict.fromkeys(['a', 'b', 'c'])
>>> dict4
{'c': None, 'b': None, 'a': None}
>>> id(dict4['a'])
9901984
>>> id(dict4['b'])
9901984
>>> id(dict4['c'])
9901984

Indeed, all of the values are the same (and the only!) None.
Now, let’s iterate, in one of a myriad number of ways, through the dict and change the value.

>>> for k, _ in dict4.items():
...    dict4[k] = []
>>> dict4
{'c': [], 'b': [], 'a': []}

Hmm. Looks the same as before!

>>> id(dict4['a'])
140150318876488
>>> id(dict4['b'])
140150324122824
>>> id(dict4['c'])
140150294277576
>>> dict4['a'].append('apples')
>>> dict4
>>> {'c': [], 'b': [], 'a': ['apples']}

But they are indeed different []s, which was in this case the intended result.

Answered By: Shawn Mehan

Answer #3:

You can use this:

l = ['a', 'b', 'c']
d = dict((k, [0, 0]) for k in l)
Answered By: g.d.d.c

Answer #4:

l = ['a','b','c']
d = dict((i, [0, 0]) for i in l)
Answered By: Yarkee
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.