Understanding List Slice Assignment In Python
Solution 1:
The answer is simple: A an assignment assigns a reference. That’s why changes to L1
are visible in L2
– they’re the same object.
A slice, however, creates a (shallow) copy of the range. Hence changes to L3
are disconnected from L2
.
In fact, in order to create a copy of a sequence, since you cannot use direct assignment, you can use a slice instead:
>>>L4 = L2[:]>>>L4.append(5)>>>L2
[1, 2, 3, 4]
… however, that’s more commonly done via the constructor, i.e. L4 = list(L2)
.
Solution 2:
To add to the answer above, the nature of the copy becomes important when you have a list of mutable objects, instead of integers or strings. The elements of the lists still point to the same objects even when you slice.
>>>a = { 'a': 0 }>>>b = { 'b' : 0 }>>>c = { 'c' : 0 }>>>l = [ a, b, c ]>>>m = l[ : 2]
m and l contain references to the same things.
>>> m
[{'a': 0}, {'b': 0}]
>>> m[0]['a'] = 1>>> m
[{'a': 1}, {'b': 0}]
>>> l
[{'a': 1}, {'b': 0}, {'c': 0}]
However, m and l are different things.
>>> m[0] = {'d': 1}
>>> m
[{'d': 1}, {'b': 0}]
>>> l
[{'a': 1}, {'b': 0}, {'c': 0}]
Solution 3:
(I wasted too much time in examples and @Konrad Rudolph beat me to the answer, I'm basically saying the same thing as him)
Python is doing the equivalent of C pointer assignment under the hood, L1 held the address for a list in memory, and L2 just copied the same address.
You can check in code, simply using the is
operator.
>>> L1 is L2
True
When using slices though, a new list must be created, since it will differ from the original one, but python, being the sneaky bastard that it is, instead of copying everything, it just copies the references to the objects inside.
Here's a more elaborate example:
>>>L1 = [1, [2, 3], 4]>>>L2 = L1>>>L2
[1, [2, 3], 4]
>>>L1[1] is L2[1]
True
Ok, so L1
holds a list with a list inside, you could replace this with a dictionary, string or any other python object. Notice that the is
operator returned True
for the list inside the list.
Then, if you do the slicing trick:
>>>L3 = L1[:2]>>>L3
[1, [2, 3]]
>>>L3 is L1
False
>>>L3[1] is L2[1]
True
The outside list has changed, but the objects within remain the same, this is known as shallow copying. In fact, the same rules keep applying, to the point if that we add a new item to the list within the list:
>>>L3[1].append(9)>>>L3
[1, [2, 3, 9]]
>>>L1
[1, [2, 3, 9], 4]
(notice the added 9) The list inside of both L1
and L3
are changed.
By contrast, you can do deepcopy
when shallow copying is not desired:
>>>from copy import deepcopy>>>L3 = deepcopy(L1)>>>L3
[1, [2, 3, 9], 4]
>>>L3 is L1
False
Post a Comment for "Understanding List Slice Assignment In Python"