Reputation: 81
>>> a = [1,2,3]
>>> b = []
>>> b.append(a)
>>> print(b)
[[1, 2, 3]]
>>> num = a.pop(0)
>>> a.append(num)
>>> print(a)
[2, 3, 1]
>>> b.append(a)
>>> print(b)
[[2, 3, 1], [2, 3, 1]]
>>>
Why is this happening and how to fix it? I need the list like
[[1, 2, 3], [2, 3, 1]]
Thank you.
Edit:
Also, why is this working?
>>> a = []
>>> b = []
>>> a = [1,2,3]
>>> b.append(a)
>>> a = [1,2,3,4]
>>> b.append(a)
>>> print(b)
[[1, 2, 3], [1, 2, 3, 4]]
>>>
'''
Upvotes: 1
Views: 303
Reputation: 15369
Every variable name in Python should be thought of as a reference to a piece of data. In your first listing, b
contains two references to the same underlying object that is also referenced by the name a
. That object gets changed in-place by the operations you’re using to rotate its members. The effect of that change is seen when you look at either of the two references to the object found in b
, or indeed when you look at the reference associated with the name a
.
Their identicality can be seen by using the id()
function: id(a)
, id(b[0])
and id(b[1])
all return the same number, which is the unique identifier of the underlying list object that they all refer to. Or you can use the is
operator: b[0] is b[1]
evaluates to True
.
By contrast, in the second listing, you reassign a
—in other words, by using the assignment operator =
you cause that name to become associated with a different object: in this case, a new list
object that you just created with your square-bracketed literal expression. b
still contains one reference to the old list, and now you append a new reference that points to this different piece of underlying data. So the two elements of b
now look different from each other—and indeed they are different objects and accordingly have different id()
numbers, only one of which is the same as the current id(a)
. b[0] is b[1]
now evaluates to False
How to fix it? Reassign the name a
before changing it: for example, create a copy:
a = list(a)
or:
import copy
a = copy.copy(a)
(or you could even use copy.deepcopy()
—study the difference). Alternatively, rotate the members a
using methods that entail reassignment rather than in-place changes—e.g.:
a = a[1:] + a[:1]
(NB immutable objects such as the tuple
avoid this whole confusion —not because they behave fundamentally differently but because they lack methods that produce in-place changes and therefore force you to use reassignment strategies.)
Upvotes: 0
Reputation: 20500
In addition to making the copy of a by doing a[:]
and assigning it to b
.
You can also use collections.deque.rotate to rotate your list
from collections import deque
a = [1,2,3]
#Make a deque of copy of a
b = deque(a[:])
#Rotate the deque
b.rotate(len(a)-1)
#Create the list and print it
print([a,list(b)])
#[[1, 2, 3], [2, 3, 1]]
Upvotes: 0
Reputation: 1440
When you append the list a
, python creates a reference to that variable inside the list b
. So when you edit the list a
, it is reflected again in the list b
. You need to create a copy of your variable and then append it to get the desired result.
Upvotes: 1
Reputation: 184455
Append a copy of your list a
, at least the first time. Otherwise, you've appended the same list both times.
b.append(a[:])
Upvotes: 2