Python遍历删除列表元素的一个奇怪bug

假定有一个Python列表,比如['CFFEX.IF', 'CFFEX.TS','SHFE.FU'],现在需要将其中带'CFFEX'前缀的所有元素都删除。在使用列表推导式一行代码搞定之前,用了一种最朴素的遍历删除方法,结果出现了意想不到的的问题。复盘了下,结论非常有意思,故记录下来,引以为戒。

方法1:用enumerate()枚举遍历,定位到元素后,使用pop()或del方法直接删除该元素。

结果输出发现,会出现删不完整的奇怪现象。正确结果应该是输出['SHFE.FU'],结果发现第2个元素未被删除!

原因解析:

enumerate()函数会返回一个游标,以及该游标位置的元素。for循环首次调用返回0,'CFFEX.IF',由于满足条件0位置元素被删除。然后进入下一次循环,此时会返回1, 'SHFE.FU',而不是我们预期的1, 'CFFEX.TS',由于原来第2个元素被跳过,导致未被删除。

根本原因,是因为删除第1个元素后,列表发生了变化,而enumerate()会基于新列表进行游标遍历,从而出现了上面的问题。

一种解决办法,就是删除元素后,游标保持不动,还保留在原位置,比如前面删除了0位置元素后,游标仍指向0,同时将列表长度减1。这个办法就是方法3的主要思路。

方法2:用for i in range(len(varieties))循环遍历删除

方法1中存在的bug依然存在,同时代码还会报错,提示游标越界!

原因也很明显,for循环里range(len(varieties))已经固定了原来列表的长度,比如本例中3个元素,range()会依次遍历0、1、2三个位置,删除0元素后,游标1会指向'SHFE.FU',出现了方法1中同样的bug,但跟方法1不同的是,它结束游标1处理后,还会继续处理游标2位置,在访问varieties[2]时报游标越界错误!方法1中没有报错,是因为它调用enumerate()不会出现越界错误。

方法3:采用笨办法,仅供演示,真实情况下不可能这么写

解决方法1的bug,具体逻辑见方法1中相关描述。

方法4:使用列表推导式,一行代码搞定,简洁优美无bug

x for x in varieties if not x.startswith(prefix)

附录:Python示例代码(jupyter环境)

改写后的代码

相关推荐
马克Markorg9 分钟前
基于LLM的大模型的RAG(检索增强生成)实现对比
python·大模型·agent·rag·企业级知识库的框架·rag 知识库
yy.y--15 分钟前
Java线程实现浏览器实时时钟
java·linux·开发语言·前端·python
Dontla20 分钟前
Python Streamlit介绍(开源Python Web应用框架,快速将Python脚本转换成交互式Web应用,适合数据科学和机器学习项目快速展示)
前端·python·开源
少云清40 分钟前
【UI自动化测试】12_web自动化测试 _验证码处理和cookie
前端·python·web自动化测试
Ama_tor1 小时前
Flask |零基础进阶(上)
后端·python·flask
喵手1 小时前
Python爬虫实战:数字时光机 - 基于 Playwright 的网页全貌归档系统(HTML + 截图)(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·playwright·零基础python爬虫教学·csv导出·网页全貌归档
@陈小鱼1 小时前
基于 Savitzky-Golay滤波器的超声图像运动分析方法
python·计算机视觉·matlab·信号处理
七夜zippoe1 小时前
属性测试革命:Hypothesis框架深度实战指南
python·性能测试·数据驱动·hypothesis·状态机测试
艾醒(AiXing-w)1 小时前
技术速递——通义千问 3.5 深度横评:纸面超越 GPT‑5.2,实测差距在哪?
人工智能·python·语言模型
喵手2 小时前
Python爬虫实战:自动化构建 arXiv 本地知识库 - 从 PDF 下载到元数据索引!
爬虫·python·自动化·arxiv·本地知识库·pdf下载·元数据索引