切片整个列表和直接分配的切片分配有什么区别?
我在许多地方看到使用list
s的片分配。 在使用(非默认)索引时,我能够理解它的用法,但我不能理解它的用法,如:
a_list[:] = ['foo', 'bar']
与那个有什么不同?
a_list = ['foo', 'bar']
?
a_list = ['foo', 'bar']
在内存中创build一个新list
,并在其中指定名称a_list
。 这与a_list
之前指出的是无关的。
a_list[:] = ['foo', 'bar']
以slice
作为索引调用a_list
对象的__setitem__
方法,并在内存list
创build一个新list
作为值。
__setitem__
计算slice
以找出它所代表的索引,并在它传递的值上调用它。 然后迭代该对象,将slice
指定范围内的每个索引设置为该对象的下一个值。 对于list
s,如果由slice
指定的范围与iterable的长度不同,则调整list
的大小。 这允许你做一些有趣的事情,比如删除一个列表的部分:
a_list[:] = [] # deletes all the items in the list, equivalent to 'del a_list[:]'
或者在列表中间插入新的值:
a_list[1:1] = [1, 2, 3] # inserts the new values at index 1 in the list
但是,对于“扩展切片”,其中step
不是一个,迭代必须是正确的长度:
>>> lst = [1, 2, 3] >>> lst[::2] = [] Traceback (most recent call last): File "<interactive input>", line 1, in <module> ValueError: attempt to assign sequence of size 0 to extended slice of size 2
切片分配到a_list
的主要内容是:
-
a_list
必须已经指向一个对象 - 该对象被修改,而不是将
a_list
指向新对象 - 该对象必须支持具有
slice
索引的__setitem__
- 右侧的对象必须支持迭代
- 没有名字指向右侧的对象。 如果没有其他的引用(例如当它是一个文字,如你的例子),它会被引用计数完成迭代后不存在。
差异是相当巨大的! 在
a_list[:] = ['foo', 'bar']
您修改了绑定到名称a_list
的现有列表。 另一方面,
a_list = ['foo', 'bar']
给名字a_list
分配一个新的列表。
也许这将有助于:
a = a_list = ['foo', 'bar'] # another name for the same list a_list = ['x', 'y'] # reassigns the name a_list print a # still the original list a = a_list = ['foo', 'bar'] a_list[:] = ['x', 'y'] # changes the existing list bound to a print a # a changed too since you changed the object
通过分配给a_list[:]
, a_list
仍然引用相同的列表对象,并修改了内容。 通过分配给a_list
, a_list
现在引用一个新的列表对象。
看看它的id
:
>>> a_list = [] >>> id(a_list) 32092040 >>> a_list[:] = ['foo', 'bar'] >>> id(a_list) 32092040 >>> a_list = ['foo', 'bar'] >>> id(a_list) 35465096
正如你所看到的,它的id
不会随着切片分配版本而改变。
两者之间的差异可能会导致完全不同的结果,例如,当列表是函数的参数时:
def foo(a_list): a_list[:] = ['foo', 'bar'] a = ['original'] foo(a) print(a)
有了这个, a
被修改了,但是如果使用a_list = ['foo', 'bar']
来代替a
,那么a
保持原来的值。