Python for in 问题

467 阅读1分钟

前几天学习群中有朋友问了一个奇怪的问题:

l = [1, 2, 3, 4, 5, 6]
for v in l:
    del l[0]
print(l)
# [4, 5, 6]

l = [1, 2, 3, 4, 5, 6]
for v in l[:]:
    del l[0]
print(l)
# []

刚看到也是觉得奇怪,平时很少会在for in 遍历时删除列表元素,第二中写法和第一种写法上只是l和l[:]不同,为什么结果会那么奇怪? 先把影响结果的因素放在这里:

  1. for in 遍历是触发可迭代对象的__iter__(),获取迭代器对象执行__next__()方法向后迭代列表
  2. 列表是使用顺序表实现的,当删除前面的元素时,后面的元素会向前移动,补上前面的空值位置,而next的位置不变(后面通过画图解释)
  3. l[:]是获取l的副本,属于浅拷贝,l[:]和l是两个不同的对象,所以当使用for in遍历l[:],是遍历的l[:],删除l中的元素不会影响对l[:]的迭代

好了,下面一点一点看一下为什么会产生以上问题:

for in 实现的while实现:

l = [1, 2, 3, 4, 5, 6]
for i in l:
    print(i)

# 等价写法:
i = 0
iter_l = iter(l)
while True:
    try:
        print(next(iter_l))
    except StopIteration as e:
        print('迭代结束')
        break

迭代列表流程图

当执行next方法时,返回当前元素,并移动到后一个元素位置,当当前位置无效时执行next方法就报错,结束循环

那如果在遍历列表时同时删除元素,会如下图

所以到会保留最后一半元素