对整个列表进行切片分配和直接分配有什么区别?

What is the difference between slice assignment that slices the whole list and direct assignment?

提问人:0xc0de 提问时间:4/15/2012 最后编辑:agf0xc0de 更新时间:7/22/2019 访问量:8284

问:

我在很多地方看到 s 使用切片赋值。当与(非默认)索引一起使用时,我能够理解它的用法,但我无法理解它的用法,例如:list

a_list[:] = ['foo', 'bar']

这与

a_list = ['foo', 'bar']

?

python 列表 变量赋值 切片

评论


答:

38赞 agf 4/15/2012 #1
a_list = ['foo', 'bar']

在内存中创建一个新名称,并将名称指向该内存。之前指出的内容无关紧要。lista_lista_list

a_list[:] = ['foo', 'bar']

调用对象的 __setitem__ 方法,并将切片作为索引,并在内存中新创建作为值。a_listlist

__setitem__计算 以确定它表示的索引,并调用它传递的值。然后,它遍历对象,将每个索引设置在对象的下一个值指定的范围内。对于 s,如果 指定的范围与可迭代对象的长度不同,则调整 的大小。这允许您执行许多有趣的事情,例如删除列表的各个部分:sliceiterslicelistslicelist

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

但是,对于“扩展切片”,如果 不是 1,则可迭代对象必须是正确的长度: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

  1. a_list必须已指向对象
  2. 修改该对象,而不是指向新对象a_list
  3. 该对象必须支持索引__setitem__slice
  4. 右边的对象必须支持迭代
  5. 没有名称指向右侧的对象。如果没有对它的其他引用(例如,当它是示例中的文本时),则在迭代完成后,它将被计数为不存在的引用。

评论

0赞 0xc0de 4/15/2012
我在文档(docs.python.org/tutorial/introduction.html#lists)中读到了这个。只是默认索引是我的怀疑:)
1赞 Sven Marnach 4/16/2012
“对于列表,如果切片指定的范围与可迭代对象的长度不同,则调整列表的大小。”仅当范围的步长值为 1 时,这才成立。对于 1 以外的步骤值,分配的可迭代对象必须生成正确数量的项。
0赞 agf 4/16/2012
@SvenMarnach 谢谢。我把它放在最后,因为我忘了提到它,我知道在某些情况下它必须是相同的长度。
16赞 Jochen Ritzel 4/15/2012 #2

差异是相当大的!在

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
3赞 Yu Hao 8/9/2015 #3

通过赋值给 ,仍然引用相同的列表对象,并修改了内容。通过赋值给 ,现在引用新的列表对象。a_list[:]a_lista_lista_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)

有了这个,也被修改了,但如果改用,则保持其原始值。aa_list = ['foo', 'bar']a

0赞 user11817711 7/22/2019 #4
a_list = ['foo', 'bar']
a=a_list[:]  # by this you get an exact copy of a_list 
print(a)
a=[1,2,3] # even if you modify a it will not affect a_list
print(a)
print(a_list)

评论

0赞 Gino Mempin 7/22/2019
问题是关于分配给 .['foo', 'bar']a_list[:]