1

I have a nested dict but when I update one dict all the others also are updated. How can I avoid that? Below is an example:

a = {}
b = {'d': [], 'e': []}
a[1] = b
a[2] = b
a[1]['e'].append([1, 2, 3])

# result: {1: {'e': [[1, 2, 3]], 'd': []}, 2: {'e': [[1, 2, 3]], 'd': []}}

Here 'e' is updated on both 1 and 2 but I want just 1 to be updated:

{1: {'e': [[1, 2, 3]], 'd': []}, 2: {'e': [], 'd': []}}
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 1
    Possible duplicate of [How to copy a dictionary and only edit the copy?](https://stackoverflow.com/questions/2465921/how-to-copy-a-dictionary-and-only-edit-the-copy) – Nosvan Aug 08 '19 at 17:11
  • [PythonTutor](http://pythontutor.com) is great for visualizing Python references. [Here's this code at the last step](http://pythontutor.com/visualize.html#code=a%20%3D%20%7B%7D%0Ab%20%3D%20%7B'd'%3A%20%5B%5D,%20'e'%3A%20%5B%5D%7D%0Aa%5B1%5D%20%3D%20b%0Aa%5B2%5D%20%3D%20b%0Aa%5B1%5D%5B'e'%5D.append%28%5B1,%202,%203%5D%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false). You can see `b`, `a[1]`, and `a[2]` all point to the same dict. – wjandrea Aug 08 '19 at 17:25

2 Answers2

2

The cloned updates occur because they're all the same dictionary, attached to different keys. It's not the case that (like you want), each dictionary is different from the other. So, if you really want separate dicts, here's one way to do that:

In [57]: def getDict():
    ...:     return {'d':[],'e':[]}
    ...: 

In [58]: a={}

In [59]: a[1] = getDict()

In [60]: a[2] = getDict()

In [61]: a[1]['e'].append([1,2,3])

In [62]: a
Out[62]: {1: {'d': [], 'e': [[1, 2, 3]]}, 2: {'d': [], 'e': []}}
wjandrea
  • 28,235
  • 9
  • 60
  • 81
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • 2
    Just to add to this, this is the concept of mutability. If `a = []` and then `b = a`, then `a` and `b` actually reference the same place in memory, they reference the same list. Changing `a` therefore changes `b`. You can check this by doing `id(a)` and `id(b)` - they will have the same Id. Dictionaries and lists are both mutable, so it is best to assign copies of these when assigning them to different variables. – Jeremy H Aug 08 '19 at 16:37
  • Why use a `getDict` function instead of `dict.copy()`? Is it because `dict.copy()` returns a shallow copy? Would `copy.deepcopy()` help? – wjandrea Aug 08 '19 at 17:02
  • 1
    @wjandrea: `copy.deepcopy` would indeed help. I just chose to go this route because I thought it would be faster (I don't have timing stats to back this up, though) – inspectorG4dget Aug 08 '19 at 17:21
0

That is the expected behaviour. When you do:

a = {}
b = {'d': [], 'e': []}
a[1] = b
a[2] = b

Actualy, a[1] "holds a reference" to b. When you modify b in a1, you are modifying "the original" b. If you want a brand new b to modify independently, use copy. If your actual dict is more complex than this, you can use deepcopy or just write by yourself a copy function.

a = {}
b = {'d': [], 'e': []}
a[1] = b.copy()
a[2] = b.copy()
a[1]['e'].append([1, 2, 3])

You can also do:

a = {}
b = {'d': [], 'e': []}
a[1] = b[:]
a[2] = b[:]
a[1]['e'].append([1, 2, 3])

This works as you expect. See also: python list by value not by reference

Nosvan
  • 151
  • 1
  • 10