不要在遍历python列表时修改列表

使用for循环遍历python列表的同时,如果增加或者删除列表里的元素将会破坏列表的迭代器,产生一些看起来很诡异的现象。

1. 使用remove 删除列表里的元素

已知一个列表,内容如下

lst = [1, 2, 3, 4, 5, 6, 7, 8]

现在要求你删除列表中的奇数,你当如何处理呢,下面是很多人想当然的一种解决方法

lst = [1, 2, 3, 4, 5, 6, 7, 8]

for i in lst:
    if i % 2 == 1:
        lst.remove(i)

print(lst)

程序输出结果

[2, 4, 6, 8]

从结果看,程序似乎是正确的,但这只是一个巧合,将列表内容替换为下面的内容

lst = [1, 3, 2, 5, 7, 9]

再次执行程序,得到的结果是

[3, 2, 7]

这究竟是为什么?

2. remove破坏了迭代器

for循环的本质是使用迭代器进行遍历,删除迭代器访问过的元素,下一次迭代中,迭代器将向后跳转1个元素。

删除元素1时,迭代器向右跳转1个元素,刚好越过了3,是remove 影响了迭代器的正常使用。

如果在for循环进行迭代时,向列表中增加元素,那么迭代器就会向左跳转1个元素,与删除的情况刚好相反。

3. 正确处理方法

想在for循环遍历列表的过程中实现删除操作,可以反向遍历列表

lst = [1, 3, 2, 5, 7, 9]

for i in reversed(lst):
    if i % 2 == 1:
        lst.remove(i)

print(lst)

第二个解决方法是复制一份列表,遍历这个复制的列表,删除原列表里的元素

import copy
lst = [1, 3, 2, 5, 7, 9]

for i in copy.copy(lst):
    if i % 2 == 1:
        lst.remove(i)

print(lst)

这样的复制是浅拷贝,因此几乎不会消耗多少内存。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案