I know that Slicing lists does not generate copies of the objects in the list; it just copies the references to them.
But if that\'s the case, then why doesn\'t this wor
For the sake of explaining it better, assume you had written
l = [1, 2, 3]
k = l[0:2]
k[-1] = 10
I hope you can agree that this is equivalent.
Now let's break down the individual statements:
l = [1, 2, 3]
This creates the following objects and references:
id object
-- --------
0 <int 1>
1 <int 2>
2 <int 3>
3 <list A>
name → id
---- --
l → 3
l[0] → 0
l[1] → 1
l[2] → 2
k = l[0:2]
This creates a new list <list B>
containing copies of the references contained in l
:
id object -- -------- 0 <int 1> 1 <int 2> 2 <int 3> 3 <list A> 4 <list B>
name → id ---- -- l → 3 l[0] → 0 l[1] → 1 l[2] → 2 k → 4 k[0] → 0 (copy of l[0]) k[1] → 1 (copy of l[1])
k[-1] = 10
First, index −1 resolves to index 1 (because k
has length 2), so this is equivalent to k[1] = 10
. This assignment means that the objects and references are updated as such:
id object -- -------- 0 <int 1> 1 <int 2> 2 <int 3> 3 <list A> 4 <list B> 5 <int 10>
name → id ---- -- l → 3 l[0] → 0 l[1] → 1 l[2] → 2 k → 4 k[0] → 0 k[1] → 5
Note how l
and l[0]
to l[2]
are not affected by this. QED.
You are right that slicing doesn't copy the items in the list. However, it does create a new list object.
Your comment suggests a misunderstanding:
# Attempting to modify the element at index 1
l[0:2][-1] = 10
This is not a modification of the element, it's a modification of the list. In other words it is really "change the list so that index 1 now points to the number 10". Since your slice created a new list, you are just changing that new list to point at some other object.
In your comment to oldrinb's answer, you said:
Why are
l[0:1]
andl[0:1][0]
different? Shouldn't they both refer to the same object, i.e. the first item ofl
?
Aside from the fact that l[0:1]
is a list while l[0:1][0]
is a single element, there is again the same misunderstanding here. Suppose that some_list
is a list and the object at index ix
is obj
. This:
some_list[ix] = blah
. . . is an operation on some_list
. The object obj
is not involved. This can be confusing because it means some_list[ix]
has slightly different semantics depending on which side of the assignment it is on. If you do
blah = some_list[ix] + 2
. . .then you are indeed operating on the object inside the list (i.e., it is the same as obj + 2
). But when the indexing operation is on the left of the assignment, it no longer involves the contained object at all, only the list itself.
When you assign to a list index you are modifying the list, not the object inside it. So in your example l[0]
is the same as l[0:2][0]
, but that doesn't matter; because your indexing is an assignment target, it's modifying the list and doesn't care what object was in there already.
Slicing a list
returns a new shallowly-copied list
object. While you are correct that it does not deep-copy the original list's items, the result is a brand new list
distinct from the original.
See the Python 3 tutorial:
All slice operations return a new list containing the requested elements. This means that the following slice returns a shallow copy of the list:
>>> squares = [1, 4, 9, 16, 25] >>> squares[:] [1, 4, 9, 16, 25]
Consider
>>> squares[:] is squares
False