DeLorean88
DeLorean88

Reputation: 647

If slice copies references why this behavior?

According to this, python copies references when slicing. I've tried the following:

>>> a=[1,2,3]
>>> b=a[:]
>>> b[1]=0
>>> a
[1, 2, 3]
>>> b
[1, 0, 3]
>>> map(id,a)
[14508376, 14508352, 14508328]
>>> map(id,b)
[14508376, 14508400, 14508328]

Why does b[1]=0 does not change a[1] (which should be the case if b[1] was indeed a reference to the same object, one might think)? Instead, it seems to generate a new reference/id and change the new object. Anywhere I can read up on this behavior in more detail?

Upvotes: 1

Views: 49

Answers (1)

chepner
chepner

Reputation: 530990

Suppose you start with a = [1,2,3]. In Python's data model, this means that a refers to an object in memory:

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3

With b = a, you simply point another name at the same object:

a -> [ * | * | * ] <- b
       |   |   |
       v   v   v
       1   2   3

b[1] = 0 changes the same reference a[1] = 0 would:

           0
           ^
           |
a -> [ * | * | * ] <- b
       |       |
       v       v
       1   2   3

(The 2 is still in memory, possibly referenced directly or indirectly via some other name, but not via a or b anymore.)


With b = a[:], you create a new list, but that new list contains references to the same object:

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^   ^   ^
       |   |   |
b -> [ * | * | * ]

Now when you write b[1] = 0, you aren't changing a[1], because a and b are distinct list objects.

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^       ^
       |       |
b -> [ * | * | * ]
           |
           v
           0

Ned Batchelder's blog post (and subsequent PyCon talk) is an excellent overview of Python's name model.

Upvotes: 5

Related Questions