Felix Z.
Felix Z.

Reputation: 317

Why does a loop through a list of lists not recognise, that a list is a copy

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?

Upvotes: 2

Views: 118

Answers (3)

LaPriWa
LaPriWa

Reputation: 1803

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

Upvotes: 1

Joshua Howard
Joshua Howard

Reputation: 916

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.

Upvotes: 1

Gilles Groven
Gilles Groven

Reputation: 141

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

Upvotes: 2

Related Questions