开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜