在Python中为切片的元素赋值

时间:2010-10-29 20:10:29

标签: python list variable-assignment slice

这是一个关于Python如何处理数据和变量的简单问题。我已经做了很多实验,并且Python大部分已经解决了,除了这让我一直绊倒:

[编辑:为了清晰起见,我将这些示例分开并重新排列]

示例1:

>>> a = [[1], 2]
>>> a[0:1]
[[1]]
>>> a[0:1] = [[5]]
>>> a
[[5], 2] # The assignment worked.

示例2:

>>> a = [[1], 2]
>>> a[0:1][0]
[1]
>>> a[0:1][0] = [5]
>>> a
[[1], 2] # No change?

示例3:

>>> a = [[1], 2]
>>> a[0:1][0][0]
1
>>> a[0:1][0][0] = 5
>>> a
[[5], 2] # Why now?

有人可以向我解释这里发生了什么吗?

到目前为止,答案似乎声称a[0:1]返回一个新列表,其中包含对a的第一个元素的引用。但我不明白这是如何解释示例1的。

3 个答案:

答案 0 :(得分:7)

a [0:1]返回一个新数组,其中包含对数组[1]的引用,因此您最终会通过引用调用修改内部数组。

第一种情况不修改[1]数组的原因是你要为复制的外部数组分配一个新的内部数组值。

底线 - a [0:1]返回数据副本,但不会复制内部数据。

答案 1 :(得分:3)

我的理解是切片返回一个新对象。那就是它的返回值是一个新列表。

因此,您无法使用赋值运算符更改原始列表的值

>>> a = [[1], 2, 3]
>>> k = a[0:2]
>>> id(a)
4299352904
>>> id(k)
4299353552
>>> 

>>> id(a)
4299352904
>>> id(a[0:2])
4299352832

还有更多的戏剧

>>> k = 5
>>> 
>>> id(k)
4298182344
>>> a[0] = [1,2]
>>> a
[[1, 2], 2, 3]
>>> id(a)
4299352904
>>> 

[编辑:问题的第二部分]

>>> a[0:1] = [[5]]

以下表示法通常也称为切片分配 内置列表的行为是原子的(删除+插入)一次性发生。我的理解是,自定义序列不允许这样做。

答案 2 :(得分:1)

有三个不同的索引操作,都转换为方法调用:

  • a[i] = b => a.__setitem__(i, b)
  • del a[i] => a.__delitem__(i)
  • a[i]用作表达式=> a.__getitem__(i)

此处abi是表达式,i可以包含使用冒号速记语法创建的slice objects。 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)

所以你的第三个例子中发生了什么:

a[0:1][0][0] = 5

变为

a.__getitem__(slice(0,1)).__getitem__(0).__setitem__(0, 5)

第一个__getitem__返回列表的一部分副本,但第二个__getitem__返回其中的实际列表,然后使用__setitem__进行修改。

另一方面,你的第二个例子变成

a.__getitem__(slice(0,1)).__setitem__(0, 5)

因此,在切片副本上调用__setitem__,原始列表保持不变。