Assigning a value to an element of a slice in Python
This is a simple question about how Python handles data and variables. I've done a lot of experimenting and have Python mostly figured out, except this keeps tripping me up:
[edit: I separated and rearranged the examples for clarity]
Example 1:
>>> a = [[1], 2]
>>> a[0:1]
[[1]]
>>> a[0:1] = [[5]]
>>> a
[[5], 2] # The assignment worked.
Example 2:
>>> a = [[1], 2]
>>> a[0:1][0]
[1]
>>> a[0:1][0] = [5]
>>> a
[[1], 2] # No change?
Example 3:
>>> a = [[1], 2]
>>> a[0:1][0][0]
1
>>> a[0:1][0][0] = 5
>>> a
[[5], 2] # Why now?
Can anybody explain to me what's going on here?
So far the answers seem to claim that a[0:1]
returns a new list containing a reference to the first element of a
. But I don'开发者_StackOverflowt see how that explains Example 1.
a[0:1] is returning a new array which contains a reference to the array [1], thus you end up modifying the inner array via a reference call.
The reason the first case doesn't modify the [1] array is that you're assigning the copied outer array a new inner array value.
Bottom line - a[0:1] returns a copy of the data, but the inner data is not copied.
My understanding is slicing returns a new object. That is it's return value is a new list.
Hence you can not use an assignment operator to changes the values of the original list
>>> a = [[1], 2, 3]
>>> k = a[0:2]
>>> id(a)
4299352904
>>> id(k)
4299353552
>>>
>>> id(a)
4299352904
>>> id(a[0:2])
4299352832
some more plays along the lines
>>> k = 5
>>>
>>> id(k)
4298182344
>>> a[0] = [1,2]
>>> a
[[1, 2], 2, 3]
>>> id(a)
4299352904
>>>
[Edit: on second part of question]
>>> a[0:1] = [[5]]
The following notation is also called commonly as slice assignment The behavior for builtin lists is atomic (delete + insert) happens in one go. My understanding is that this is not allowed for custom sequence.
There are three distinct operations with indices, all are translated to method calls:
a[i] = b
=>a.__setitem__(i, b)
del a[i]
=>a.__delitem__(i)
a[i]
used as an expression =>a.__getitem__(i)
Here a
, b
and i
are expressions, and i
can contain slice objects created using the colon shorthand syntax. E.g.:
>>> class C(object):
... def __setitem__(self, *a):
... print a
...
>>> C()[1] = 0
(1, 0)
>>> C()['foo'] = 0
('foo', 0)
>>> C()['foo':'bar'] = 0
(slice('foo', 'bar', None), 0)
>>> C()['foo':'bar',5] = 0
((slice('foo', 'bar', None), 5), 0)
So what's happening in your third example is this:
a[0:1][0][0] = 5
becomes
a.__getitem__(slice(0,1)).__getitem__(0).__setitem__(0, 5)
The first __getitem__
returns a copy of part of the list, but the second __getitem__
returns the actual list inside that, which is then modified using __setitem__
.
Your second example on the other hand becomes
a.__getitem__(slice(0,1)).__setitem__(0, 5)
So __setitem__
is being called on the sliced copy, leaving the original list intact.
精彩评论