为什么list.remove()的行为不像人们预期的那样?

时间:2011-08-26 21:07:03

标签: python

from pprint import *

sites = [['a','b','c'],['d','e','f'],[1,2,3]]

pprint(sites)

for site in sites:
        sites.remove(site)

pprint(sites)

输出:

[['a', 'b', 'c'], ['d', 'e', 'f'], [1, 2, 3]]
[['d', 'e', 'f']]

为什么不是None,或者是空列表[]?

3 个答案:

答案 0 :(得分:20)

这是因为你在迭代它时修改了一个列表。你永远不应该这样做。

对于类似这样的事情,你应该复制一下这个列表并对其进行迭代。

for site in sites[:]:
    sites.remove(site)

答案 1 :(得分:6)

因为在迭代它时调整集合的大小是Python相当于C和C ++中未定义的行为。您可能会遇到异常或巧妙的错误行为。只是这样做。在这种特殊情况下,可能发生的事情是:

  • 迭代器以索引0开头,存储它在索引0处,并为您提供存储在该索引处的项目。
  • 您删除索引0处的项目,之后的所有内容都会向左移动一个以填充该洞。
  • 要求迭代器提供下一个项目,并忠实地将索引增加1,将1作为新索引存储,并为您提供该索引处的项目。但由于remove操作引起的项目移动,索引1处的项目是从索引2(最后一项)开始的项目。
  • 你删除它。
  • 要求迭代器提供下一个项目,但是当下一个索引(2)超出范围(现在只有0..0)时,会发出迭代结束信号。

答案 2 :(得分:2)

通常我会期望迭代器因为修改连接列表而纾困。使用字典,这至少会发生。

为什么不删除d,e,f的东西?我只能猜测:迭代器可能有一个内部计数器(或者甚至只是基于 getitem 的“回退迭代协议”)。

予。例如,产生的第一个项目是sites[0],i。即['a', 'b', 'c']。然后将其从列表中删除。

第二个是sites[1] - [1, 2, 3],因为索引已经改变。这也被删除了。

第三个是sites[2] - 但由于这将是一个索引错误,迭代器会停止。