2

I encountered a (in my opinion) extremely strange behavior, when looping through a list of lists. It is very difficult to explain, but here is an example code:

k = [[0],[1],[2]]

for lis in k:
    lis_copy = lis
    lis_copy.append(0)
    print lis

When executing this, I get:

[0, 0]
[1, 0]
[2, 0]

This is very strange for me, as the list which is appended is a copy of lis, but lis is appended as well. I would assume this list to be untouched. For example doing the same with a list of integers the following happens:

k = [0,1,2]

for num in k:
    num_copy = num
    num_copy = 0
    print num

Output:

0
1
2

Just as expected num is not touched by the manipulation of num_copy.

If somebody could explain why this is happening and how to avoid this, like how to disconnect the lis_copy from is, that would be great.

Wow, I am amazed I did not encounter mayor problems before, without knowing this. I think I should review quiet some of my code. Anyway I thought this is somehow connected to the loop, this seems not to be the case, therefore I think the best explanation can be found here:

How to clone or copy a list?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Felix Z.
  • 317
  • 2
  • 12
  • http://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy – Patrick Haugh Dec 15 '16 at 16:14
  • https://docs.python.org/3/library/copy.html – Patrick Haugh Dec 15 '16 at 16:15
  • I think you're missing some key knowledge about Python here - read this for an overview of calling be reference and calling by name: http://www.python-course.eu/passing_arguments.php – wilfo Dec 15 '16 at 16:15
  • lis_copy = lis does not create a new list, it simply points to the original list. Python3 has a copy method but I think you have to slice the list to copy in 2.7. Something like lis_copy = list[:] – donners45 Dec 15 '16 at 16:17

3 Answers3

2

This is because Python lists (and dicts) are not copied to a new list, but the new list becomes a reference to that list. if you truly want to copy the list, use deepcopy

Gilles Groven
  • 121
  • 1
  • 1
  • 5
  • can you give an example, why a copy of the list with reference is needed, I just wondered where the advantage of that behavior is ? – Felix Z. Dec 16 '16 at 00:36
1

Case a:

k = [[0],[1],[2]]

for lis in k:
    lis_copy = lis
    lis_copy.append(0)
    print lis

We have a pointer to a list, and inside the loop we have another pointer made that points to the inner list objects. Then a zero is appended to each object.

Case b:

k = [0,1,2]

for num in k:
    num_copy = num
    num_copy = 0
    print num

We have a pointer to a list, and inside the loop we have another pointer made that points to the inner integers. The difference is that in this case the pointer is changed to then point to a zero object rather than the list elements.

Joshua Howard
  • 876
  • 1
  • 12
  • 25
1

You could use copy.copy() or copy.deepcopy()to avoid this behavior:

import copy

k = [[0],[1],[2]]

for lis in k:
    lis_copy = copy.copy(lis)
    lis_copy.append(0)
    print lis

Output:

[0]
[1]
[2]

Source: https://docs.python.org/2/library/copy.html

LaPriWa
  • 1,787
  • 1
  • 12
  • 19