'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 |
