0

I have 2 lists :

l1 = [[1,2,3],[4,5,6],[7,8,9]]
l2 = list(l1)

According to this post if I modify l2, l1 should not change.

But if I do the following:

del l2[1][1] 

l1 will be modified as well.

Is this intended and how can I prevent it from happening? I also noticed that the ids of l1[1] and l2[1] are the same.

Community
  • 1
  • 1
LeS
  • 19
  • 1
  • 1
    Think of the lists as treasure maps. Your `l1` has three treasures marked on it, and you copied the map on a different paper (`l2`). Any lines you draw on your new treasure map won't affect the old one. However, if you take one treasure off, and both maps will lose one of their treasures (sure it's still visible on the map, but you get the idea). The maps are different, but the treasures are the same. This same applies to your Python lists; the elements are still the same, but removing or adding more elements to one list wont do the same to the other one. – Markus Meskanen Oct 27 '16 at 11:23

3 Answers3

2

list(l1) will make a shallow copy of l1; that is, all references inside the list l1 will be copied to the new list. Modifications to these nested lists will be visible in the original list since you modify objects with the same reference.

Take a look at the matching ids for the lists:

print("l1 object references: ", *map(id, l1))
l1 object references:  139927285488584 139927284661256 139927284723784

print("l2 object references: ", *map(id, l2))
l2 object references:  139927285488584 139927284661256 139927284723784

If you didn't have lists in lists, this wouldn't be an issue:

l1 = [1,2,3]
l2 = list(l1)    
del l2[1]    
print(l1)  # [1, 2, 3]
print(l2)  # [1, 3]

The solution is, instead of using list, use copy.deepcopy:

import copy

l1 = [[1,2,3],[4,5,6],[7,8,9]]
l2 = copy.deepcopy(l1)
del l2[1][1]
print(l1)  # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Now the ids of the nested lists are different and mutating one leaves the other alone:

print("l1 object references: ", *map(id, l1))
l1 object references:  139927284726984 139927284737160 139927284737800

print("l2 object references: ", *map(id, l2))
l2 object references:  139927284710216 139927285123976 139927284678344

Of course, a list comprehension where list is called on every element also suffices in achieving the same effect :-)

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
1

This is because you have a list of lists. If instead you write:

l2 = [list(li) for li in l1]

You will be able to delete or modify elements of l2 without changing l1. This is because, when one has a list of lists, l2 = list(l1) creates a copy of the outer list, but the inner lists of l2 are still references to the original inner lists of l1. So, if you change elements in the inner lists of l2, these changes will be reflected in the original inner lists in l1. If you create explicit copies of the inner lists of l1, as I did above, you avoid this problem.

Angus Williams
  • 2,284
  • 19
  • 21
-1

This is what you are looking for:

l2 = [i[:] for i in l1]

This works because you need to actually copy the inner lists by value, not the outer one, in order for them to be completely seperate.

Here is an example on how this works:

l1 = [[1,2,3],[4,5,6],[7,8,9]]
l2 = [i[:] for i in l1]
l2[0][0]=3
print (l2) #[[3, 2, 3], [4, 5, 6], [7, 8, 9]]
print (l1) #[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
SiGm4
  • 284
  • 1
  • 2
  • 10