我以为我理解了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']
)。
答案 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']
它有效。
答案为什么在上面的评论中(因为你正在使用副本)