Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing a value in one list changes the values in another list with a different memory ID

I have been beating my head against a wall over this problem. I create a list and make 4 copies, only one of which shares the same memory index. If I change the original list, is somehow changes 3 of those copies as well, 2 of which have a different memory index. Only if I make a list using the same command as the original, am I able to create a list that is not impacted by changes to the original. How is this possible? Here is the output from my console:

>>> orig=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> id(orig)
151498220
>>> copy1=orig   #same index
>>> id(copy1)
151498220
>>> copy2=orig[:]   #different index
>>> id(copy2)
151498348
>>> copy3=list(orig)   #different index
>>> id(copy3)
151503020
>>> copy4=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> id(copy4)
151498636
>>> orig[0][1]=34
>>> copy1
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]   #expected, same memory index
>>> copy2
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]   #WTF?!?!?
>>> copy3
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]   #ARGH!!!
>>> copy4
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]   #workaround?
>>> id(orig)
151498220
>>> id(copy1)
151498220
>>> id(copy2)
151498348
>>> id(copy3)
151503020
>>> id(copy4)
151498636

The memory indices did not change and yet the lists were altered. Only copy1 should have changed as it has the same memory index as orig.

like image 851
Adrian Reich Avatar asked Dec 26 '22 00:12

Adrian Reich


1 Answers

That's because you are just creating a shallow copy. You need to create a deep copy instead.

As per copy module doc:

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

You can verify it by comparing the id of inner list:

>>> orig=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> id(orig)
151498220
>>> copy2=orig[:]   #different index
>>> id(copy2)
151498348

>>> id(copy2[0]) == id(orig[0])  # inner list have same id
True

You can create a deepcopy using copy.deepcopy(x):

>>> import copy
>>> 
>>> copy3 = copy.deepcopy(orig)
>>> 
>>> id(copy3[0]) == id(orig[0])   # inner list have different id
False

>>> orig[0][3] = 34
>>> 
>>> orig
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> copy3
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
like image 192
Rohit Jain Avatar answered May 16 '23 00:05

Rohit Jain