4

I want to create a dictionary using two lists as keys

regions = ['A','B','C','D']
subregions = ['north', 'south']
region_dict = dict.fromkeys(regions, dict.fromkeys(subregions))

this produces the dictionay I want correctly:

{'A': {'north': None, 'south': None},
 'B': {'north': None, 'south': None},
 'C': {'north': None, 'south': None},
 'D': {'north': None, 'south': None}}

However, if I try to update one of elements in this dict, I see that other elements are also being updated

region_dict['A']['north']=1
>>> {'A': {'north': 1, 'south': None},
     'B': {'north': 1, 'south': None},
     'C': {'north': 1, 'south': None},
     'D': {'north': 1, 'south': None}}

I am not sure what exactly I'm doing wrong here. How can I update just one of the values in this dictionary?

igrolvr
  • 343
  • 4
  • 13
  • @zvone: It's the same symptom, but I don't consider `list` multiplication to be obviously similar to what `dict.fromkeys` does, at least for people with less Python experience. I did link that question in my answer, but it's not a duplicate. – ShadowRanger Jul 28 '20 at 14:22
  • Although the underlying causes are very similar, I agree it's not a duplicated question. Thanks for the very useful feedback – igrolvr Jul 28 '20 at 14:44

2 Answers2

11

You can't use dict.fromkeys when the value to use with each key is mutable; it uses aliases of the same value as the value for every key, so you get the same value no matter which key you look up. It's basically the same problem that occurs with multiplying lists of lists. A simple solution is to replace the outer dict.fromkeys with a dict comprehension:

region_dict = {region: dict.fromkeys(subregions) for region in regions}
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
1

Just to make you more clear.

Here dict.fromkeys(subregions) this is one separate object (which every key's value is pointed to), so whenever you change value of this object using one key, the same is going to get reflected on all the other keys referring to this object.

To explain through code, that would look something like this:

temp = dict.fromkeys(subregions)
region_dict = {region: temp for region in regions}

So when you put dict.fromkeys(subregions) inside the dict comprehension, every time a new object is going to get created. That's the reason there will be no problem with that.

Sai Sreenivas
  • 1,690
  • 1
  • 7
  • 16