Home > Software engineering >  Incorrectly appending/concat. to list at bottom of nested Python dictionary
Incorrectly appending/concat. to list at bottom of nested Python dictionary

Time:02-22

When I created a nested dictionary structure I ran into a issue where when I tried to append an item to a list in the nested dictionary, it would append that item too all lists across all levels of my nested dictionary that had the corresponding final key.

d = {"p": [], "d": []}
d = {value: dict(d) for value in [1,2,3]}
d = {value: dict(d) for value in ["h", "i"]}

d
Out[14]: 
{'h': {1: {'p': [], 'd': []}, 2: {'p': [], 'd': []}, 3: {'p': [], 'd': []}},
 'i': {1: {'p': [], 'd': []}, 2: {'p': [], 'd': []}, 3: {'p': [], 'd': []}}}

When I start to populate my "bottom-level" dictionaries' lists using append(), this happens:

d["h"][1]["p"].append("Please Help")

d
Out[16]: 
{'h': {1: {'p': ['Please Help'], 'd': []},
  2: {'p': ['Please Help'], 'd': []},
  3: {'p': ['Please Help'], 'd': []}},
 'i': {1: {'p': ['Please Help'], 'd': []},
  2: {'p': ['Please Help'], 'd': []},
  3: {'p': ['Please Help'], 'd': []}}}

As seen above, the string was appended to each list in d that had the final key 'p'. Using concatenation of lists produces a similar, but different result:

d = {"p": [], "d": []}
d = {value: dict(d) for value in [1,2,3]}
d = {value: dict(d) for value in ["h", "i"]}

d["h"][1]["p"] = d["h"][1]["p"]   ["Please Help"]

d
Out[23]: 
{'h': {1: {'p': ['Please Help'], 'd': []},
  2: {'p': [], 'd': []},
  3: {'p': [], 'd': []}},
 'i': {1: {'p': ['Please Help'], 'd': []},
  2: {'p': [], 'd': []},
  3: {'p': [], 'd': []}}}

Here, the string was added to lists that shared the same 2nd- and 3rd-level key (1 and 'p', respectively). I do not understand what is happening and any help would be appreciated. This is on Python 3.7.

CodePudding user response:

Like @Mark says you need to use copy...

from copy import deepcopy as dc

d = {"p": [], "d": []}
d = {value: dc(d) for value in [1,2,3]}
d = {value: dc(d) for value in ["h", "i"]}

d["h"][1]["p"].append("Please Help")

print(d)
#{'h': {1: {'p': ['Please Help'], 'd': []}, 2: {'p': [], 'd': []}, 3: {'p': [], 'd': []}}, 'i': {1: {'p': [], 'd': []}, 2: {'p': [], 'd': []}, 3: {'p': [], 'd': []}}}

CodePudding user response:

When you do d = {value: dict(d) for value in [1,2,3]}, you don't create three distinct dictionaries inside d. You have the same dictionary repeated three times. Similarly for d = {value: dict(d) for value in ["h", "i"]}. So when you do d["h"][1]["p"].append("Please Help"), you are appending 'Please Help' to the one dictionary. Since the other "bottom level" dictionary is the same dictionary, you see the same string over and over again.

As an analogy, you can think of each variable as a box with a number on it. When you do d = {value: dict(d) for value in [1,2,3]}, you're putting the same box number in the dictionary three times, you aren't creating three different boxes. When you tell Python to change the value of the "first" box, it goes to the box with that box number, and changes what's in that box. Since all the "other" boxes refer to that same box, what you see when you look at those "other" boxes is also changed.

You can fixed this by doing {value: dict(d).copy() for value in [1,2,3]}.

  • Related