Alex Kir
Alex Kir

Reputation: 97

Filling a python dictionary in for loop returns same values

For the needs of the project im iterating over some data and adding needed values to premade dictionary.

here is striped down example of code which represents my question:

class Parser:
    def __init__(self):
        self.records = [['value1','value2','value3'], 
                        ['value4','value5','value6'],
                        ['value7','value8','value9']]
    def get_parsed(self):
        parsed = []
        dic = {'key1': '',
               'key2': '',
               'key3': '',
               }
        for i in self.records:
            dic['key1'] = i[0]
            dic['key2'] = i[1]
            dic['key3'] = i[2]
            parsed.append(dic)
        return parsed

What i expect to get is list of dicts like this:

[{'key1':'value1','key2':'value2','key3':'value3'},
 {'key1':'value4','key2':'value5','key3':'value6'},
 {'key1':'value7','key2':'value8','key3':'value9'}]

But what im getting is:

[{'key1':'value1','key2':'value2','key3':'value3'},
 {'key1':'value1','key2':'value2','key3':'value3'},
 {'key1':'value1','key2':'value2','key3':'value3'}]

Though if i move dictionary initialization into 'for' loop - im getting the desired result but i don't understand why is that happening?

EDIT: The question is more "Why does it happens this way" I did some testing in ipython and that's what i've got:

In [1]: d = {'a':'','b':'','c':''}

In [2]: d
Out[2]: {'a': '', 'b': '', 'c': ''}

In [3]: d['a'] = 'value'

In [4]: d['b'] = 'other_value'

In [5]: d['c'] = 'third_value'

In [6]: d
Out[6]: {'a': 'value', 'b': 'other_value', 'c': 'third_value'}

In [7]: d['a'] = 'inserting new value'

In [8]: d
Out[8]: {'a': 'inserting new value', 'b': 'other_value', 'c': 'third_value'}

So the value of the key could be updated and it changes, why doesn't it happen in FOR loop?

Upvotes: 4

Views: 9416

Answers (2)

BrenBarn
BrenBarn

Reputation: 251598

Because your dic is created outside the loop, you only create one dict. If you want three different dicts, you need to create three different dicts, so move the initial creation of dic inside the loop.

To answer your updated question, the issue is that although you think you are appending a new dict with each parsed.append(dic), you are just appending the same dict three times. Append doesn't copy the dict. So whenever you modify that dict, all the dicts in parse show the change, since they are all the same dict. This version of your second code example may be more illustrative:

>>> d = {'a': '', 'b': '', 'c': ''}
>>> stuff = []
>>> stuff.append(d)
>>> print stuff
[{'a': '', 'c': '', 'b': ''}]
>>> d['a'] = 'other'
>>> print stuff
[{'a': 'other', 'c': '', 'b': ''}]
>>> stuff.append(d)
>>> print stuff
[{'a': 'other', 'c': '', 'b': ''}, {'a': 'other', 'c': '', 'b': ''}]
>>> d['a'] = 'yet another'
>>> print stuff
[{'a': 'yet another', 'c': '', 'b': ''}, {'a': 'yet another', 'c': '', 'b': ''}]

Notice that changing the dict "works" in that it indeed changes the value, but regardless of that, the list still contains the same dict multiple times, so any changes you make overwrite whatever changes you made earlier. In the end, your list only contains the last version of the dict, because all earlier changes were overwritten in all dicts in the list.

Upvotes: 6

Mark Byers
Mark Byers

Reputation: 839194

You are modifying and inserting the same dictionary to your list three times. Create a new dictionary for each iteration of the loop:

for i in self.records:
    dic = { 'key1': i[0], 'key2': i[1], 'key3': i[2] }
    parsed.append(dic)

Upvotes: 6

Related Questions