2011-08-26 54 views
3
from pprint import * 

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

pprint(sites) 

for site in sites: 
     sites.remove(site) 

pprint(sites) 

输出:为什么list.remove()的行为不如人们所期望的那样?

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

为何不能无,或空列表[]?

+5

我不在python中工作,所以我不确定,但可能是因为你在修改列表的同时迭代它。当你这样做时,很多奇怪的事情往往会发生。 –

回答

14

这是因为您正在修改列表,因为您正在迭代它。你永远不应该那样做。

对于这样的事情,你应该制作一个列表的副本并对其进行迭代。

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

或者只是做'del sites [:]'... – glglgl

+5

'你永远不应该这样做'值得更多的重视。 – job

+2

谢谢。我绝不会这样做。 –

6

因为在迭代时重新调整集合的大小是Python与C和C++中的未定义行为相当。您可能会遇到异常或错误的行为。只是不要做到这一点。在这种特殊情况下,有什么引擎盖下有可能发生的情况是:

  • 迭代器索引为0,存储,这是在指数0开始,并让您存储的索引处的项目。
  • 您删除索引为0的项目,然后将所有项目向左移动一个以填充该孔。
  • 迭代器被要求输入下一个项目,并忠实递增索引值1,将1存储为新索引,并为该索引项提供该项。但是由于remove操作导致物品移动,因此索引1处的物品是索引2(最后一个物品)处开始的物品。
  • 您删除。
  • 迭代器被要求提供下一个项目,但是当下一个索引(2)超出范围(现在只是0..0)时表示迭代结束。
+0

Python中没有任何东西真的等同于C或C++的未定义行为,除非可能通过深度魔法手动使用字节码。迭代时修改集合的行为方式相当可预见。只是它们都不是特别有用,即使它们是,你也可以用其他方式更清楚地写出相同的东西。 –

+0

@Karl:(1)据我所知,结果没有记录在任何地方,只是说它“不安全”。这会使行为成为实现细节。 (2)只要你坚持一个版本的实现,C和C++中的一些未定义的行为也是相当可预测的;)但是,如果你觉得挑剔,你是对的,它不像严重未定义的行为。 – delnan

2

通常我会想到迭代保释,因为修改连接列表出来。用字典,这至少会发生。

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

I.即,第一项是产生sites[0]岛即['a', 'b', 'c']。然后从列表中删除。

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

而第三个是sites[2] - 但因为这是一个索引错误,迭代停止。

相关问题