2

The following demo code:

mydict = {}
mylist = []

mydict["s"] = 1
mydict["p"] = "hasprice"
mydict["o"] = 3
print(mydict)
mylist.append(mydict)

mydict["s"] = 22
mydict["p"] = "hasvat"
mydict["o"] = 66
print(mydict)
mylist.append(mydict)

print(mylist)

prints out the following result:

[{'s': 22, 'p': 'hasvat', 'o': 66}, {'s': 22, 'p': 'hasvat', 'o': 66}]

and the only explanation that comes to my mind is that mydict is assigned by reference and therefore the list items all point to a same memory object. Is this the reason?

How can I properly append multiple different dictionaries to the list?

I am building each mydict dictionary within a loop and then wanted to append it to the list which I will finally write to a JSON file.

halfer
  • 19,824
  • 17
  • 99
  • 186
Robert Alexander
  • 875
  • 9
  • 24
  • 1
    Correct. The list contains the same dict object twice. – sj95126 Oct 27 '22 at 14:10
  • 1
    If like your example the keys are the same for each dictionary, you could write a function which takes the values as parameters and constructs a new dictionary with the common keys and new values. Something like `make_dict(22,"hasvat",66)`. As an added benefit this will avoid the aliasing problem that you are facing. – John Coleman Oct 27 '22 at 14:16
  • 1
    The `id` function is a good function for testing if two things point to the same object. Evaluating `id(mydict[0])` and `id(mydict[1])` would have confirmed your correct suspicion that the list items point to the same thing. – John Coleman Oct 27 '22 at 14:28

2 Answers2

3
mylist.append(mydict)

So, what are you doing here? You're appending a dict object, right?

The problem is that in Python the dict is a mutable type, which gets passed by reference.

That's why when you edit mydict you're also editing mylist[0], because they both reference to the same object.


To achieve what I think you want to do, simply do this instead:

mylist.append(mydict.copy())

This creates a copy which no more refers to mydict.

The copy should be done when first calling .append, otherwise you'll anyway get two identical dicts, as @sj95126 pointed out.


To better understand my answer, I strongly suggest to read the following:

FLAK-ZOSO
  • 3,873
  • 4
  • 8
  • 28
  • 1
    Might want to clarify whether you're copying the dict in the first `append()` or the second. In the second `append()` the values have already been changed. – sj95126 Oct 27 '22 at 14:19
  • 1
    Thanks a lot. Very clear and also instructive. I prefer this solution since in my application mydict["s"] is initialized to a long complex hash which never changes, only p and o do change. – Robert Alexander Oct 27 '22 at 14:50
2
mydict = {}
mylist = []

mydict["s"] = 1
mydict["p"] = "hasprice"
mydict["o"] = 3
print(mydict)
mylist.append(mydict)

mydict = {}  # This is a second dictionary

mydict["s"] = 22
mydict["p"] = "hasvat"
mydict["o"] = 66
print(mydict)
mylist.append(mydict)

print(mylist)

You'll get:

[{'s': 1, 'p': 'hasprice', 'o': 3}, {'s': 22, 'p': 'hasvat', 'o': 66}]

David Rubio
  • 144
  • 10
  • 1
    Thank you very much David. So the new initialization does allocate a new memory space, right? Very clear. I upvoted your simpler solution but chose FLAK's as the reply since in my real application the first member of the dictionary is initialized to a long hash that never changes and I don't have to reassign it each time in the loop. – Robert Alexander Oct 27 '22 at 14:52