更新切片列表

时间:2016-01-14 08:15:11

标签: python list

我以为我理解了Python切片操作,但当我尝试更新切片列表时,我感到困惑:

>>> foo = [1, 2, 3, 4]
>>> foo[:1] = ['one'] # OK, foo updated
>>> foo
['one', 2, 3, 4] 
>>> foo[:][1] = 'two' # why foo not updated?
>>> foo
['one', 2, 3, 4] 
>>> foo[:][2:] = ['three', 'four'] # Again, foo not updated
>>> foo
['one', 2, 3, 4] 

为什么foo[:][1] = 'two'之后没有更新foo?

更新:也许我没有清楚地解释我的问题。我知道切片时会创建一个新列表。我怀疑是切片分配更新列表的原因(例如foo[:1] = ['one']),但如果有两个切片级别,则不会更新原始列表(例如foo[:][2:] = ['three', 'four'])。

4 个答案:

答案 0 :(得分:19)

foo[:]foo的副本。你改变了副本。

答案 1 :(得分:17)

这是因为python 具有可以分配的 l 值。相反,一些表达式有一个赋值形式,这是不同的。

FIND="`find $TOSAVE -mindepth 1 -type d \( -path $TOSAVE/backup \) -prune -o -mtime -1 -print`" 是一种语法糖:

foo[something]

foo.__getitem__(something) 是一种相当不同的语法糖:

foo[something] = bar

切片只是foo.__setitem__(something, bar) 的一个特例,因此something扩展为

foo[x:y]

foo.__getitem__(slice(x, y, None)) 扩展为

foo[x:y] = bar

现在带有切片的foo.__setitem__(slice(x, y, None), bar) 会返回一个新列表,该列表是指定范围的副本,因此修改它不会影响原始数组。并且通过__getitem__作为一种不同的方法来分配作品,这可以简单地做其他事情。

然而,特殊任务处理仅适用于最外层的操作。成分是正常的表达。所以当你写

__setitem__

它扩展到

foo[:][1] = 'two'

foo.__getitem__(slice(None, None, None)).__setitem__(1, 'two') 部分创建副本,foo.__getitem__(slice(None, None, None))修改该副本。但不是原始阵列。

答案 2 :(得分:13)

此处需要注意的主要事项是foo[:]将返回自身的副本,然后索引[1]将在已复制的已返回的列表中应用

# indexing is applied on copied list
(foo[:])[1] = 'two'
    ^
copied list

如果保留对复制列表的引用,则可以查看此内容。因此,foo[:][1] = 'two'操作可以重写为:

foo = [1, 2, 3, 4]

# the following is similar to foo[:][1] = 'two'

copy_foo = foo[:]  
copy_foo[1] = 'two'

现在,copy_foo已被更改:

print(copy_foo)
# [1, 'two', 3, 4]

但是,foo保持不变:

print(foo)
# [1, 2, 3, 4]

在您的情况下,您没有使用foo复制foo[:]列表来命名中间结果,也就是说,您没有保留对它的引用。在'two'分配到foo[:][1] = 'two'后,中间复制列表不再存在

答案 3 :(得分:3)

使用

foo[1]  = 'two'

foo[2:] = ['three', 'four']

它有效。

答案为什么在上面的评论中(因为你正在使用副本)