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

atv*_*atv 33 python list

我写了一个简单的python程序

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

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

经过调试后,我可以发现i它正在增加并且列表正在减少.
但是,我有循环终止条件i < len(l).那我为什么会收到这样的错误呢?

Mar*_*off 51

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

看起来像你想要做的是:

l = [x for x in l if x != 0]
Run Code Online (Sandbox Code Playgroud)

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

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

i = 0
while i < len(l):
   if l[i] == 0:
       l.pop(i)
   else:
       i += 1
Run Code Online (Sandbox Code Playgroud)


Jon*_*erg 17

len(l)评估range()内置函数时,表达式仅进行一次计算.此时构建的范围对象不会改变; 它不可能知道关于这个对象的任何信息l.

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


8da*_*day 6

什么马克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)
Run Code Online (Sandbox Code Playgroud)

它就像一座从上到下倒塌的高楼:即使它在倒塌的中间,你仍然可以“进入”它并参观尚未倒塌的楼层。


jat*_*ism 5

你正在迭代它时改变列表的大小,这可能不是你想要的,是你的错误的原因.

编辑:正如其他人已经回答和评论的那样,列表推导更好地作为首选,尤其是回答这个问题.出于这个原因,我提出这个替代方案,虽然不是最好的答案,但它仍然解决了问题.

所以在那个注释中,你也可以使用filter,它允许你调用一个函数来评估你不想要的列表中的项目.

例:

>>> l = [1,2,3,0,0,1]
>>> filter(lambda x: x > 0, l)
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

活到老,学到老.简单就是更好,除非你需要复杂的东西.

  • 你甚至不需要lambda,因为0的计算结果为False.`filter(None,l)` (3认同)