'for x in list:' 和 'for x in list[:]:' 有什么区别?

6

我正在学习pygame,书上出现了这两种符号:

for x in xs:
    # do something with x

for x in xs[:]:
    # do something with x

它们的意思相同吗?
2个回答

12

xs[:] 复制了列表。

  • for x in xs -- 直接迭代列表 xs
  • for x in xs[:] -- 迭代列表 xs 的一个副本。

"迭代副本" 的一个原因是为了对原始列表进行内部修改。 "复制" 的另一个常见原因是您处理的数据的原子性。(即:另一个线程/进程在您读取它时修改了列表或数据结构)。

注意: 但请注意,就地修改仍然可能会修改您已复制的原始列表的索引。

示例:

# Remove even numbers from a list of integers.
xs = list(range(10))
for x in xs[:]:
    if x % 2 == 0:
        xs.remove(x)

3
这还是有点危险,不是吗?如果你需要删除中间的一个元素,然后在最后,如果我想得正确的话,可能会出现IndexError错误。 - TheSoundDefense
这就是重点,你在迭代一个副本的同时修改了原始数据。因此,在副本中可能会有一些索引不再存在于原始数据中。 - TheSoundDefense
好的,它仍然回答了他的问题,所以我相信一切都很好 :) - TheSoundDefense
当我知道需要读取值或仅修改每个值时(例如将每个元素乘以2),我会使用for x in xs:。而当我需要通过删除/添加元素来更改列表的大小时,我会使用for x in xs [:]:。哦,这有意义,因为在我的书中,它被用于从列表中删除移动到屏幕外的敌人。我可以看出在迭代循环时删除项目会引起问题的原因。 - TheEyesHaveIt
3
如果你使用list.remove(x)而不是del x[i],之前的例子可以工作。一个更好的例子可能是添加元素而不是删除它们:for x in xs[:]: if x % 2: xs.append(x)这将添加所有奇数元素的额外副本。如果没有切片,你将会一直循环。 - Blckknght

3

它们基本上是同义词,但是当您在循环体内修改列表时,情况就不同了。形式list[:]在迭代列表之前显式地对列表进行副本,使您可以在循环迭代期间自由地修改原始列表(例如通过删除项目)。不建议在直接迭代列表时从其中删除项目。


你可能想谈论一下如果L包含自定义类的实例,而我执行for x in L[:]: x.increment()会发生什么。这些调用的副作用将被浅复制忽略。 - inspectorG4dget
那并不是修改列表,而是修改其他对象。两件事情并不完全相同。 - Greg Hewgill
好的解释,现在完全明白了。 - TheEyesHaveIt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接