How does assignment work with list slices?
You are confusing two distinct operation that use very similar syntax:
1) slicing:
b = a[0:2]
This makes a copy of the slice of a
and assigns it to b
.
2) slice assignment:
a[0:2] = b
This replaces the slice of a
with the contents of b
.
Although the syntax is similar (I imagine by design!), these are two different operations.
When you specify a
on the left side of the =
operator, you are using Python's normal assignment, which changes the name a
in the current context to point to the new value. This does not change the previous value to which a
was pointing.
By specifying a[0:2]
on the left side of the =
operator, you are telling Python you want to use slice assignment. Slice assignment is a special syntax for lists, where you can insert, delete, or replace contents from a list:
Insertion:
>>> a = [1, 2, 3]>>> a[0:0] = [-3, -2, -1, 0]>>> a[-3, -2, -1, 0, 1, 2, 3]
Deletion:
>>> a[-3, -2, -1, 0, 1, 2, 3]>>> a[2:4] = []>>> a[-3, -2, 1, 2, 3]
Replacement:
>>> a[-3, -2, 1, 2, 3]>>> a[:] = [1, 2, 3]>>> a[1, 2, 3]
Note:
The length of the slice may be different from the length of theassigned sequence, thus changing the length of the target sequence, ifthe target sequence allows it. - source
Slice assignment provides similar function to tuple unpacking. For example, a[0:1] = [4, 5]
is equivalent to:
# Tuple Unpackinga[0], a[1] = [4, 5]
With tuple unpacking, you can modify non-sequential lists:
>>> a[4, 5, 3]>>> a[-1], a[0] = [7, 3]>>> a[3, 5, 7]
However, tuple unpacking is limited to replacement, as you cannot insert or remove elements.
Before and after all these operations, a
is the same exact list. Python simply provides nice syntactic sugar to modify a list in-place.
I came across the same question before and it's related to the language specification. According to assignment-statements,
If the left side of assignment is subscription, Python will call
__setitem__
on that object.a[i] = x
is equivalent toa.__setitem__(i, x)
.If the left side of assignment is slice, Python will also call
__setitem__
, but with different arguments:a[1:4]=[1,2,3]
is equivalent toa.__setitem__(slice(1,4,None), [1,2,3])
That's why list slice on the left side of '=' behaves differently.