Python for循环遍历列表删除元素时未遍历全部元素的原因
问题产生原因
核心原因是遍历列表的同时原地删除列表元素,会触发列表的索引动态收缩,导致遍历游标和实际元素位置错位,最终漏过部分元素。
你提供的问题代码如下:
def remove_over_5(list): i=0 for n in list: if n > 5: del list[i] i += 1 return list print(remove_over_5([1,2,3,4,5,6,7,8,9])) # 实际运行输出:[1, 2, 3, 4, 5, 7, 9]
逐轮拆解执行逻辑就能看到错位的过程:
- Python的
for循环遍历列表时,是按迭代游标逐次取当前列表对应位置的元素,不会在循环开始时预先生成固定的元素副本 - 前5轮循环遍历元素1-5,都不满足大于5的删除条件,
i正常从0自增到5,列表无变化 - 第6轮循环取到索引5位置的元素6,满足删除条件,执行
del list[5]:删除后列表会自动收缩内存,原本在索引6的7会前移到索引5位置,索引7的8前移到索引6,索引8的9前移到索引7 - 删除完成后
i自增到6,下一轮循环直接取当前列表索引6位置的元素(也就是前移后的8),刚好跳过了已经挪到索引5位置的7 - 遍历到8时再次触发删除,删掉索引6位置的8后,9会前移到索引6位置,此时
i自增到7,已经超出当前列表的最大索引范围(删除8后列表长度为7,索引范围为0-6),循环直接终止,9也被漏过
*额外提醒:不要用list作为参数/变量名,它是Python内置的列表构造类,直接覆盖会导致后续无法正常调用list()方法。
正确实现方案
不要在正向遍历原列表时直接修改原列表,可参考以下两种稳定实现:
- 方案1:遍历原列表,筛选符合保留条件的元素构建新列表返回,逻辑最直观不易出错,推荐优先使用
def remove_over_5(input_list): # 列表推导式简写版本 return [n for n in input_list if n <= 5]
- 方案2:如果必须原地修改原列表,改用倒序遍历,从列表末尾往头部遍历删除,此时删除元素只会影响已经遍历过的尾部索引,不会打乱未遍历元素的位置
def remove_over_5(input_list): for i in range(len(input_list)-1, -1, -1): if input_list[i] > 5: del input_list[i] return input_list
内容的提问来源于stack exchange,提问作者Marty
相关产品推荐
相关产品推荐

