Reputation: 357
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.
Upvotes: 4
Views: 4680
Reputation: 601649
All values of dict2
are actually the same list instance, since passing []
to dict.fromkeys()
only creates one list instance. Try
dict2 = {v: [] for v in dict1.values()}
Upvotes: 7
Reputation: 123463
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']
Upvotes: 0
Reputation: 43024
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.
Upvotes: 2
Reputation: 798676
The problem is that dict.fromkeys()
initializes each item with the same object.
dict2 = dict((x, []) for x in dict1.values())
Upvotes: 0
Reputation: 318508
Iterate over yourdict.keys()
(this returns a list so it will not be affected by any change to the dict)
Upvotes: 0