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.)