deckardk deckardk - 1 month ago 8
Python Question

Python: setting values of a list of nested dictionaries in class instances

I have a burning question that I just can't figure out. Let's say you have a class, and this class takes in as input a list of nested dictionaries. It initializes one of the keys of each of these dictionaries with a new, empty dictionary. Later, I want to set one of the nested values of an object in the list as something. For some reason this seems to affect other objects in the list?

I know that's sounds very convoluted, so here's an example:

class Tester():
def __init__(self, stuff):

# stuff is a list of dictionaries
self.stuff = stuff

# Each item in the list should be initialized to this dictionary
inside_init_dict = {'test': True}
for x in self.stuff:
x['info'] = inside_init_dict

if __name__ == '__main__':
new_stuff = [{'info': {}}, {'info': {}}, {'info': {}}]
mytest = Tester(new_stuff)

print(mytest.stuff)
# >>> [{'info': {'test': True}}, {'info': {'test': True}}, {'info': {'test': True}}]

# I want to just set a value in the nested dict of the first item in the list
mytest.stuff[0]['info']['test'] = False

# However, all items in the list change
print(mytest.stuff)
# >>> [{'info': {'test': False}}, {'info': {'test': False}}, {'info': {'test': False}}]


This happens on both Python 2 and 3. The only way I can get around this is to not use the separate variable "inside_init_dict", and directly set the initialized dictionary:

class Tester():
def __init__(self, stuff):

# stuff is a list of dictionaries
self.stuff = stuff

# Each item in the list should be initialized to this dictionary
for x in self.stuff:
x['info'] = {'test': True}

if __name__ == '__main__':
new_stuff = [{'info': {}}, {'info': {}}, {'info': {}}]
mytest = Tester(new_stuff)

print(mytest.stuff)
# >>> [{'info': {'test': True}}, {'info': {'test': True}}, {'info': {'test': True}}]

mytest.stuff[0]['info']['test'] = False

# This is what I want
print(mytest.stuff)
# >>> [{'info': {'test': False}}, {'info': {'test': True}}, {'info': {'test': True}}]


What's going on here? I have tried setting the variable "inside_init_dict" in various places, like as a class variable or outside the class. The issue still occurs.

Answer

Assign the keys to different copies of the inside_init_dict dictionary instead of the same one:

    ...
    inside_init_dict = {'test': True}
    for x in self.stuff:
        x['info'] = inside_init_dict.copy()