'Python: How can I modify dictionary values in a for loop alternating the keys?

I am new to Python (and to programming).

I'd like to modify a dictionary in a for loop by alternating the key of the dictionary. I wrote the following code, which was unsccessful, however:

#coding: utf-8
dict1 = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
dict2 = dict.fromkeys(dict1.values(),[])

for key in dict2:
    if key == 'value1':
        dict2[key].extend(['test1', 'test2'])
    elif key == 'value2':
        dict2[key].extend(['test3', 'test4'])
    elif key == 'value3':
        dict2[key].extend(['test5', 'test6'])

print (dict2['value1'])
print (dict2['value3'])

I expected the results to be:

 ['test5', 'test6']
 ['test1', 'test2']

but I actually got:

 ['test5', 'test6', 'test3', 'test4', 'test1', 'test2']
 ['test5', 'test6', 'test3', 'test4', 'test1', 'test2']

I guess the problem might come from my making the dictionary from another dictionary using "dict.fromkeys", but I couldn't see why it is problematic even if it is the case.

Thanks for your attention. Looking forward to your suggestions.



Solution 1:[1]

The problem is you used a mutable object as the value initializer. It is the very same object for each value.

Python2> dict1 = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
Python2> dict2 = dict.fromkeys(dict1.values(),[])
Python2> dict2
{'value1': [], 'value2': [], 'value3': []}
Python2> dict2['value1']
[]
Python2> id(dict2['value1'])
43895336
Python2> id(dict2['value2'])
43895336
Python2> id(dict2['value3'])
43895336

So you are extending the same list.

Solution 2:[2]

Iterate over yourdict.keys() (this returns a list so it will not be affected by any change to the dict)

Solution 3:[3]

The problem is that dict.fromkeys() initializes each item with the same object.

dict2 = dict((x, []) for x in dict1.values())

Solution 4:[4]

As others have pointed-out, the problem is that your call to dict.fromkeys() associates a reference to the same empty list with each key it creates in the new dictionary. An easy solution is to make dict2 a defaultdict class from the collections module and make the default value a separate newly created empty list:

from collections import defaultdict

dict1 = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
dict2 = defaultdict(list)

for key in dict1.itervalues():
    if key == 'value1':
        dict2[key].extend(['test1', 'test2'])
    elif key == 'value2':
        dict2[key].extend(['test3', 'test4'])
    elif key == 'value3':
        dict2[key].extend(['test5', 'test6'])

print dict2['value1']
# ['test1', 'test2']
print dict2['value3']
# ['test5', 'test6']

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Keith
Solution 2 ThiefMaster
Solution 3 Ignacio Vazquez-Abrams
Solution 4 martineau