Reputation: 95
This is my code:
a = []
res = []
for i in range(0, 3):
a.append(i)
res.append(a)
print(res)
The result is:
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
But I want the result to be:
[[0], [0, 1], [0, 1, 2]]
I know the solution is using the shallow copy: res.append(a[:])
. But can somebody tell me why?
Upvotes: 1
Views: 3770
Reputation: 39354
a = [] # (1) list created here
res = []
for i in range(0, 3):
a.append(i) # (2) list modified here
res.append(a) # (3) res is modified here
print(res)
What your code is saying is this:
At (1) a list
is created and a
refers to this list
.
At (2) you modify the list
from (1), but the list itself remains at the same memory location and a
still refers to this list.
At (3) you just make a copy of a reference and add it to res
, and still neither a
nor the list at (1) change.
The end results is that res
gets 3 copies of the reference to the list at (1).
Here is a side effect:
a[1] = 42
print(res)
Output:
[[0, 42, 2], [0, 42, 2], [0, 42, 2]]
You say that you know that this is the code you are after:
a = []
res = []
for i in range(0, 3):
a.append(i)
res.append(a[:]) # (4) new list created
print(res)
At (4) a new list is created whose contents is the same as the list that a
refers to. This new list is not referred to by a
, but instead, one of the elements of res
has a reference to this new list.
Firstly this means that res
holds references to lists, which is why they hang around long enough to be printed. Secondly a
still refers to the original list.
Here is a side effect:
a[1] = 42
print(res)
Output:
[0, 42, 2] [[0], [0, 1], [0, 1, 2]]
However, this is not the end of the story if you examine this code:
a = []
res = []
for i in range(0, 3):
a.append([i]) # (5) Create a new list with one element
res.append(a[:]) # (6) Shallow copy as above
print(res)
a[1].append(42)
print(a, res)
Output:
[[[0]], [[0], [1]], [[0], [1], [2]]]
[[0], [1, 42], [2]] [[[0]], [[0], [1, 42]], [[0], [1, 42], [2]]]
This occurs because at (6) there was only a shallow copy made.
Upvotes: 1
Reputation: 21
When you append a to the res array, you are appending a pointer to the a variable. Not the 'value' of the a variable. So when you are done, the res array has the 'value' - [a, a, a].
When you shallow copy, you are copying the 'value' of the a variable at that stage of the loop into the res array, giving you a 'value' of - [[0],[0,1],[0,1,2]].
Upvotes: 2
Reputation: 21
when you append the object "a", python actually appends a pointer that points to the original list "a". In the next iteration of the loop you change the original object, so all of the pointers to that object show the latest state of the object. you can add print the lists in every iteration to see that in action. What you want is to create a copy of "a", that would remain unchanged, and append the copy to "res". Like you said, using the syntax a[:] would do the job.
Upvotes: 2
Reputation: 49803
You appended the same thing (a
) to res
three times, so it appears 3 times. The fact that you changed the contents of a
between each call to append
doesn't matter. If each call to append
was given its own copy of a
, then you'd get the result you expect.
Upvotes: 6