为什么修改迭代序列是不安全的?

时间:2010-07-27 18:29:37

标签: python

  

修改循环中迭代的序列是不安全的(这只能发生在可变序列类型中,例如列表)。如果您需要修改正在迭代的列表(例如,复制所选项目),则必须迭代副本。切片表示法使这特别方便:

   >>> for x in a[:]: # make a slice copy of the entire list
   ...    if len(x) > 6: a.insert(0, x)
   ... 
   >>> a
   ['defenestrate', 'cat', 'window', 'defenestrate']

为什么只做for x in a ??

是不安全的

3 个答案:

答案 0 :(得分:15)

没有太过技术化:

如果你在Python中迭代一个可变序列并且在迭代过程中改变了序列,那么将会发生什么事情并不总是很清楚。如果在迭代过程中在序列中插入一个元素,那么现在可以合理地将其视为序列中的“下一个”元素?如果删除下一个对象怎么办?

出于这个原因,在您更改它时迭代可变序列会导致未指定的行为。任何事情都可能发生,具体取决于列表的实现方式。 : - )

答案 1 :(得分:13)

这是许多语言中的常见问题。如果您有一个线性数据结构,并且您正在迭代它,那么必须跟踪您在结构中的位置。它可能是当前索引或指针,但它是某种指向“当前位置”的指针。

如果在迭代发生时修改列表,则该游标可能不正确。

一个常见的问题是你删除了光标下的项目,一切都向下滑动了一下,循环的下一次迭代会增加光标,你无意中跳过了一个项目。

某些数据结构实现提供了在迭代时删除项目的功能,但大多数都没有。

答案 2 :(得分:1)

当您修改迭代迭代器的集合时,可能会出现意外行为,例如丢失项目或两次返回相同的项目。

这个代码在我运行时无限循环:

>>> a = [ 'foo', 'bar', 'baz' ]
>>> for x in a:
...    if x == 'bar': a.insert(0, 'oops')

这是因为迭代器使用索引来跟踪它在列表中的位置。在列表的开头添加一个项会导致再次返回项目“bar”而不是迭代器前进到下一个项目。