python:列表索引超出范围错误

我写了一个简单的Python程序

l=[1,2,3,0,0,1] for i in range(0,len(l)): if l[i]==0: l.pop(i) 

这给了我错误'列表索引超出范围'在线if l[i]==0:

debugging后,我可以看出, i越来越增加,列表正在减less。
但是,我有循环终止条件i < len(l) 。 那为什么我得到这样的错误?

在迭代时,您正在减less列表的长度,因此当您在范围语句中接近索引的末尾时,其中一些索引不再有效。

看起来你想要做的是:

 l = [x for x in l if x != 0] 

这将返回一个没有任何元素为零的副本(顺便说一下,该操作被称为列表理解 )。 甚至可以缩短最后一部分,只要if x ,因为非零数字评估为True

在你写代码的方式中,不存在i < len(l)的循环终止条件,因为len(l)是在循环之前预先计算的,而不是在每次迭代中重新计算。 但是你可以用这种方式写:

 i = 0 while i < len(l): if l[i] == 0: l.pop(i) else: i += 1 

expression式len(l)仅在一个时间range()被评估,此时评估内buildrange() 。 此时构build的范围对象不会改变; 它不可能知道任何关于对象的信息。

PS l是一个糟糕的名字! 它看起来像数字1,或大写字母I.

您在迭代时正在更改列表的大小,这可能不是您想要的,并且是错误的原因。

编辑:正如其他人已经回答和评论,列表parsing更好作为首选,特别是在回应这个问题。 我提出这个作为替代的原因,虽然不是最好的答案,但它仍然解决了这个问题。

所以在这个笔记上,你也可以使用filter ,它允许你调用一个函数来评估你不想要的列表中的项目。

例:

 >>> l = [1,2,3,0,0,1] >>> filter(lambda x: x > 0, l) [1, 2, 3] 

活到老,学到老。 除了当你需要复杂的东西时,简单更好。

Mark Rushakoff所说的是真实的,但是如果在相反的方向上迭代,也可以从for循环中的列表中删除元素。 例如,

 x = [1,2,3,0,0,1] for i in range(len(x)-1, -1, -1): if x[i] == 0: x.pop(i) 

它就像一座高大的楼房,从上到下,即使在倒塌的过程中,你仍然可以“进入”它,并访问尚未倒塌的楼层。

问题在于你试图在使用列表len()的循环中修改你引用的列表。 当您从列表中删除项目,然后新的len()计算在下一个循环。

例如,在第一次运行后,当您删除(i)使用l.pop(i)时,发生了成功,但是在下一个循环中列表的长度发生了变化,所以所有的索引号都被移位了。 循环试图运行在一个短的列表抛出错误。

在循环之外这样做是有效的,但是最好在循环之前首先声明和清空列表,然后在循环中将所有你想要保留的东西添加到新列表中,这样会更好地构build新列表。

对于那些可能会遇到同样问题的人。

列表理解将导致你的解决scheme。

但正确的方式来复制python中的对象是使用python模块副本 – 浅和深层复制操作。

 l=[1,2,3,0,0,1] for i in range(0,len(l)): if l[i]==0: l.pop(i) 

如果不是这个,

 import copy l=[1,2,3,0,0,1] duplicate_l = copy.copy(l) for i in range(0,len(l)): if l[i]==0: m.remove(i) l = m 

然后,你自己的代码将工作。 但是为了优化,列表理解是一个很好的解决scheme。

我正在使用Python 3.3.5。 以上使用while循环的解决scheme对我来说并不适用。 即使我把print (i)之后len(l)它给了我一个错误。 我在命令行运行相同的代码(shell)[运行函数时popup的窗口],它运行时没有错误。 我所做的是在主程序的函数外部计算len(l),并将长度作为parameter passing。 有效。 Python有时候很奇怪。