Python for-in-loop 停止对从 for-in-loop 创建的列表对象的迭代

Python for-in-loop stops iteration on list object created from for-in-loop

[来自第一个 Stack-o-flow Python 初学者的第一个问题]

我一直在尝试创建一个函数,将数字 1 附加到 10,然后在 python 列表对象中从 10 擦除到 1。 然而,我成功了,我遇到了 for-in 循环的奇怪行为。

以下是我所做的并取得了成功:

def a():
    li = []

    for i in range(1,11):
        li.append(i)
        print(li)

    for n in range(1,11):
        li.remove(li[-1])
        print(li)

a()

将打印:

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5]
[1, 2, 3, 4]
[1, 2, 3]
[1, 2]
[1]
[]

但是,如果我将其 for 循环的第二部分 range(1,11) 更改为 li,迭代将停止,如下所示。

def a():
    li = []

    for i in range(1,11):
        li.append(i)
        print(li)

    for n in li:         <-------------- THIS PART
        li.remove(li[-1])
        print(li)

a()

将打印:

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5]

所以,我检查了对象的长度li

def a():
    li = []
    for i in range(1,11):
        li.append(i)
        print(li)

    print("Length before passed: ", len(li))

    for n in li: <------------ THIS
        print("Length BEFORE REMOVE: ", len(li))

        li.remove(li[-1])

        print("Length AFTER REMOVE: ", len(li))
        print(li)
a()

将打印:

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Length before passed:  10
Length BEFORE REMOVE:  10
Length AFTER REMOVE:  9
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Length BEFORE REMOVE:  9
Length AFTER REMOVE:  8
[1, 2, 3, 4, 5, 6, 7, 8]
Length BEFORE REMOVE:  8
Length AFTER REMOVE:  7
[1, 2, 3, 4, 5, 6, 7]
Length BEFORE REMOVE:  7
Length AFTER REMOVE:  6
[1, 2, 3, 4, 5, 6]
Length BEFORE REMOVE:  6
Length AFTER REMOVE:  5
[1, 2, 3, 4, 5] <---- And it stops here.

这是怎么回事? 为什么 python for 循环会在其完整循环之前停止?

非常感谢。

试试运行这个,马上就明白了

def a():
    li = []

    for i in range(1,11):
        li.append(i)
        print(li)

    for n in li:
        print(n)
        li.remove(li[-1])
        print(li)

a()

删除元素会发生这种情况:

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1
[1, 2, 3, 4, 5, 6, 7, 8, 9]
2
[1, 2, 3, 4, 5, 6, 7, 8]
3
[1, 2, 3, 4, 5, 6, 7]
4
[1, 2, 3, 4, 5, 6]
5
[1, 2, 3, 4, 5]

在您的例子中,迭代停止是因为您从头开始迭代,但同时从末尾删除元素:

  • 第一次迭代以 9 个元素结束,因此循环继续到第二个元素。
  • 第二次迭代以 8 个元素结束,因此循环进行到第三个元素
  • ...
  • 第 5 次迭代以 5 个元素结束,没有第 6 个元素可继续,循环结束。

这就是为什么在迭代列表时改变列表通常是不可取的。

add 然后打印 10 次,你 remove 然后打印 10 次 - 简化:

a = []
a.append(1)
print(a)         # [1]
a.pop()
print(a)         # []

您从一个空列表开始并在添加后打印 - 您从一个空列表停止并打印。

第二个代码部分的问题是:您在迭代时修改可迭代对象 - 这通常不是一个好主意。


如果你改变:

def a():
    li = []

    for i in range(1,11):
        li.append(i)
        print(li)

    while(li):
        li.pop()  # same but easier - removes last element without params
        if(li):   # test if non empty
            print(li)

或优化:

    for _ in  range(len(li)-1): # one less so it stops bevore removing the last elem
        li.pop()
        print(li)

你得到了想要的输出。

这是因为您从头到尾迭代列表,并且总是删除最后一个元素。当 remove 方法更改列表和来自 python 的 for-in 循环考虑这种更改时,您迭代前五个 itens 并删除最后五个。

我的建议是这样做:

def a():
  li = []

  for i in range(1,11):
    li.append(i)
    print(li)

  print("Length before passed: ", len(li))

  # Remove the last item while has items
  while len(li):
    li.pop()