Python Forum
Adding to the dictionary inside the for-loop - weird behaviour - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Adding to the dictionary inside the for-loop - weird behaviour (/thread-32097.html)



Adding to the dictionary inside the for-loop - weird behaviour - InputOutput007 - Jan-20-2021

I want to write a program in which as an input I take a list consisted of words which can contain punctuation marks. I built a dictionary where keys are elements of a given list and values are empty lists. My goal is to add to these lists (inside the this dictionary) the indexes of those chars from the words which are punctuation marks. The program works partially - the problem is, that it adds the proper index to the previous list, i. e. to the list for the previous key, not for the current one. If you analyze the code, you will see what I mean:
list1 = ['!,', 'Hey!']
dict_words = dict.fromkeys(list1, [])
print(list1)
print(dict_words)
print()
for word in list1:    
  counter_punc = 0
  print('"word": ', word, ' dict_words["word"]: ', dict_words[word])
  if word.isalpha():
    print("alpha word: ", word)
  else:
    print("non-alpha word: ", word)
    for letter in word:
      if letter.isalpha():
        print("alpha letter: ", letter) #, " non-alpha word: ", word)
      else:
        counter_punc += 1
        dict_words[word].append(word.index(letter))
        print("letter: ", letter, " index: ", word.index(letter))
        print('"word": ', word, ' dict_words["word"]: ', dict_words[word])
        # dict_words[word].append()
  print("word: ", word, " counter_punc: ", counter_punc)
  print()
Iterating through the items of this dictionary:
for k,v in dict_words.items():
  print(k,v)
we obtain that for both keys we have the same value, i. e.
[0,1,3]
It is incorrect - it should be for the key
'!,'
the value
[0,1]
and for the key
'Hey!'
the value
[3]


Could anyone point me where the bug is and how to fix it?
I would be grateful for help.


RE: Adding to the dictionary inside the for-loop - weird behaviour - BashBedlam - Jan-20-2021

It's the line :

dict_words = dict.fromkeys(list1, [])
That's causing the trouble. I'm not sure how you would use the method fromkeys differently in order to correct the problem but if you replace that line with :
dict_words = {'!,': [], 'Hey!': []}
then your code will produce the expected results.


RE: Adding to the dictionary inside the for-loop - weird behaviour - Larz60+ - Jan-20-2021

here's what I get:
>>> list1 = ['!,', 'Hey!']
>>> dict_words = dict.fromkeys(list1, [])
>>> for k, v in dict_words.items():
...     print(f"k: {k}, v: {v}")
... 
k: !,, v: []
k: Hey!, v: []
>>>



RE: Adding to the dictionary inside the for-loop - weird behaviour - Serafim - Jan-20-2021

fromdict takes a list of keys and a value and assigns that value to all keys. If you send a list as value, all keys share the same list. When you print the dictionary you can see that all keys have an empty list but you can't see that it is the same list and that the keys share it. The only way get around the problem is as @BashBedlam indicates.


RE: Adding to the dictionary inside the for-loop - weird behaviour - buran - Jan-20-2021

spam = ['foo', 'bar']
eggs = dict.fromkeys(spam, [])
print(eggs)
print([id(item) for item in eggs.values()])
Output:
{'foo': [], 'bar': []} [140175770726664, 140175770726664]
lists are mutable and as you can see all keys refer to same object (same id). Update is reflected in all of them.

you can do eggs = {key:[] for key in spam}
alternatively, you can use collections.defaultdict with default value being list


RE: Adding to the dictionary inside the for-loop - weird behaviour - InputOutput007 - Jan-21-2021

Hey guys! Thank you all for the explanation and spending your time helping me.
Thank you: @BashBedlam, @Larz60+, @Serafim, @buran :)