Search code examples
pythondictionaryfor-loopappendkey

Why do my previous dictionaries in a list change when I try to add a new one?


I have a code that does the following: Goes through a list of dictionaries, fills up a "temporary" dictionary with each one's data, and then appends the "temporary" dictionary to an "information" list.

However, I've noticed that every time the "temporary" dictionary changes, the overall "information" list changes as well.

This is a test code that perfectly represents the issue that I'm having:

dict1 = {"Name":"Maria", "Age":"22"}
dict2 = {"Name":"Ryley", "Age":"23"}
dict3 = {"Name":"Helen", "Age":"24"}

all_dicts = [dict1, dict2, dict3]

temp_dict ={}

info = []

for dict in all_dicts:
    print ("CURRENT DICT: " + dict["Name"])
    
    print ("Info before loop: " + str(info))
    #Temporary loop.
    for key in dict:
        temp_dict[key] = dict[key]
    print ("Info after loop: " + str(info))
    
    info.append(temp_dict)

When this is run, the "info" variable is different before and after the "temporary loop" despite the fact that it's the "temp_dict" variable that is changing. This is the output:

CURRENT DICT: Maria
Info before loop: []
Info after loop: []
CURRENT DICT: Ryley
Info before loop: [{'Name': 'Maria', 'Age': '22'}]
Info after loop: [{'Name': 'Ryley', 'Age': '23'}]
CURRENT DICT: Helen
Info before loop: [{'Name': 'Ryley', 'Age': '23'}, {'Name': 'Ryley', 'Age': '23'}]
Info after loop: [{'Name': 'Helen', 'Age': '24'}, {'Name': 'Helen', 'Age': '24'}]

I understand that the way to fix this would be to replace the "temporary loop" with this:

temp_dict = dict

But I would really like to understand why this is happening. The line above and the "temporary loop" should virtually be doing the same thing, so why is the "info" variable changing retroactively as the "temp_dict" variable does? Is there a way to prevent this besides my solution above?


Solution

  • The problem is that you create a single temp_dict outside of the loop and keep updating and appending that one dict to info. With each run of the temporary loop, you are changing the single dict that is referenced multiple times in the list.

    The solution is to create temp_dict in the loop. You also print "Info after loop" before adding the dict to info, missing the data you just built up in the inner loop.

    dict1 = {"Name":"Maria", "Age":"22"}
    dict2 = {"Name":"Ryley", "Age":"23"}
    dict3 = {"Name":"Helen", "Age":"24"}
    
    all_dicts = [dict1, dict2, dict3]
    
    
    info = []
    
    for dict in all_dicts:
        temp_dict ={}
        print ("CURRENT DICT: " + dict["Name"])
    
        print ("Info before loop: " + str(info))
        #Temporary loop.
        for key in dict:
            temp_dict[key] = dict[key]
    
        info.append(temp_dict)
        print ("Info after loop: " + str(info))
    

    outputs

    CURRENT DICT: Maria
    Info before loop: []
    Info after loop: [{'Name': 'Maria', 'Age': '22'}]
    CURRENT DICT: Ryley
    Info before loop: [{'Name': 'Maria', 'Age': '22'}]
    Info after loop: [{'Name': 'Maria', 'Age': '22'}, {'Name': 'Ryley', 'Age': '23'}]
    CURRENT DICT: Helen
    Info before loop: [{'Name': 'Maria', 'Age': '22'}, {'Name': 'Ryley', 'Age': '23'}]
    Info after loop: [{'Name': 'Maria', 'Age': '22'}, {'Name': 'Ryley', 'Age': '23'}, {'Name': 'Helen', 'Age': '24'}]
    

    To note, you can do this in fewer steps

    dict1 = {"Name":"Maria", "Age":"22"}
    dict2 = {"Name":"Ryley", "Age":"23"}
    dict3 = {"Name":"Helen", "Age":"24"}
    
    all_dicts = [dict1, dict2, dict3]
    
    info = [d.copy() for d in all_dicts]