python列表操作remove()遇到的坑

如果你只是想知道解决方法不想知道为什么的话,直接在迭代的时候给列表后面加上[::-1]即可,然后就不用往后看了

前言

remove是列表删除元素的三剑客之一,因为他可以直接填写元素项,因此十分好用,我也很喜欢,其实上半年用列表的时候就遇到了报错这个问题,找到了解决方法,但是刚刚有同学问我remove删除元素删除不干净的问题,我想了想,还是写一篇博客吧。

案例介绍

我们创建一个列表,把里面的33和44删掉,每次循环打印一下元素,最后打印一下列表

ls = [11,22,33,44,55]
for i in ls:
    print(i)
    if i == 33 or i == 44:
        ls.remove(i)
print(ls)

执行结果

11
22
33
55
[11, 22, 44, 55]

首先我们可以看到,打印的元素根本就没有44,为什么呢?我们来详细一下

原因分析

其实在执行代码的时候,for循环的i依次代表每个元素,那大家有没有想过为什么可以取得到每一个元素呢?是怎么取的呢?这个迭代的底层原理是怎样的呢?我们一起来看看吧

for循环的这种遍历取值功能本质上是利用了迭代器的原理,如果你不知道什么是迭代器,没关系,我简单和你解释一下:

在这里插入图片描述
你创建的这个数据结构的内存空间是一定的,虽然会动态改变。迭代器就相当从第一个数据走到最后一个数据,每次做一次迭代,就会往后面迈一步,但如果你把前面的元素移除了,后面的元素就依次往前补,这就导致了你想删除的元素可能已经逃离到了安全区。

其实有同学可能会思考,这家伙不就是索引吗?其实也可以这么理解吧,但是这个索引最大值是动态改变的,你每次删除一个元素,这个索引的最大值就减一了。

来,咱们就以上面的例子为谈一下为啥会有问题

  • 程序正老老实实的循环迭代,直到i为33的时候
  • 未删除33的时候列表是[11,22,33,44,55],删除了之后是[11,22,44,55]
  • 此时继续往后迭代,小箭头继续往后走,也就是遇到了55,44已经逃离到安全区了

那么为什么for循环会如此简洁?这是因为for循环底层我们做了:

  • 第一,调用可迭代对象的__iter__方法,将goods转化为迭代器goods_iterator;
  • 第二,调用迭代器goods_iterator的__next__方法,返回出goods的第一个元素;
  • 第三,循环步骤2,直到迭代器内数据流全部输出,捕获异常()

解决方案

迭代列表的时候加上[::-1]

ls = [11,22,33,44,55]
for i in ls[::-1]:
    print(i)
    if i == 33 or i == 44:
        ls.remove(i)
print(ls)

输出结果

55
44
33
22
11
[11, 22, 55]

那为什么这样可以呢?因为我们的迭代是从最后开始的,依次往前,这样就不会出现后面元素移位到前面这一说了,因为我们删除就是从后往前删除的啊,可以好好吸收一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笼中小夜莺

嘿嘿嘿,请用金钱尽情地蹂躏我吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值