Python 当'pop'-循环一个元素而'for'循环一个列表时发生了什么

Python 当'pop'-循环一个元素而'for'循环一个列表时发生了什么,python,python-2.7,list,for-loop,Python,Python 2.7,List,For Loop,代码: 以及输出: arr = [ i for i in xrange(10) ] for i in arr: if i in arr: print i arr.pop(0) print arr 为什么会有这样的结果?不应该是[]?在迭代时,不建议修改序列(或映射)。它会弄乱内部指针 例如,下面的代码永远不会结束 $ python2.7 ts.py 0 2 4 6 8 [5, 6, 7, 8, 9] 根据: 注意:当序列被 循环(这仅适用于可变序列,即列表)。一 内

代码:

以及输出:

arr = [ i for i in xrange(10) ]

for i in arr:
  if i in arr:
    print i
    arr.pop(0)

print arr

为什么会有这样的结果?不应该是
[]

在迭代时,不建议修改序列(或映射)。它会弄乱内部指针

例如,下面的代码永远不会结束

$ python2.7 ts.py 
0
2
4
6
8
[5, 6, 7, 8, 9]
根据:

注意:当序列被 循环(这仅适用于可变序列,即列表)。一 内部计数器用于跟踪下一个使用的项目,以及 这在每次迭代中递增。当这个计数器到达 循环终止的序列长度这意味着如果 套件从序列中删除当前(或上一个)项 将跳过下一项(因为它获取当前项的索引) 如果套件插入 在当前项之前的序列中,当前项将 下次通过循环再次处理。这会导致严重的后果 可以通过使用一个片段创建临时副本来避免的bug 整个序列,例如

arr = [1,2,3]
for i in arr:
    print i
    arr.append(i)
[:]中x的
:
如果x<0:a.移除(x)

显然,你说的是:

for x in a[:]:
   if x < 0: a.remove(x)

因为,正如@falsetru所提到的,不建议在迭代过程中更改序列,但在本例中,for循环基于一个常量值,即
arr
的长度。每个
pop()
都将删除第一个元素,列表将逐渐清空。

在迭代时更新序列会产生一些意外的结果,这就是为什么从不建议这样做。下图描述了变量
i
在每次从列表中弹出时的变化

for i in range(len(arr)):
    arr.pop(0)
var指令
i[0,1,2,3,4,5,6,7,8,9]
|因为我在arr^
|____________________________________|
|                                    |
|五
|arr.pop(0)[1,2,3,4,5,6,7,8,9]
|     
|对于arr中的i[1,2,3,4,5,6,7,8,9]
|                                       ^
|_______________________________________|
|_______________________________________|
|                                       |
|五
|arr.pop(0)[2,3,4,5,6,7,8,9]
|     
|对于arr中的i[2,3,4,5,6,7,8,9]
|                                          ^
|__________________________________________|
|__________________________________________|
|                                          |
|五
|arr.pop(0)[3,4,5,6,7,8,9]
|     
|对于arr中的i[3,4,5,6,7,8,9]
|                                             ^
|_____________________________________________|
|_____________________________________________|
|                                             |
|五
|arr.pop(0)[4,5,6,7,8,9]
|     
|对于arr中的i[4,5,6,7,8,9]
|                                                ^
|________________________________________________|
|________________________________________________|
|                                                |
|五
|arr.pop(0)[5,6,7,8,9]

通过添加枚举,更容易看到发生了什么:

var    Instruction                    <--------- arr -------------> 
 i                                   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 |     for i in arr                   ^
 |____________________________________|
 |                                    |
 |                                    V
 |     arr.pop(0)                    [1, 2, 3, 4, 5, 6, 7, 8, 9]
 |     
 |     for i in arr                  [1, 2, 3, 4, 5, 6, 7, 8, 9]
 |                                       ^
 |_______________________________________|
 |_______________________________________|
 |                                       |
 |                                       V
 |     arr.pop(0)                    [2, 3, 4, 5, 6, 7, 8, 9]
 |     
 |     for i in arr                  [2, 3, 4, 5, 6, 7, 8, 9]
 |                                          ^
 |__________________________________________|
 |__________________________________________|
 |                                          |
 |                                          V
 |     arr.pop(0)                    [3, 4, 5, 6, 7, 8, 9]
 |     
 |     for i in arr                  [3, 4, 5, 6, 7, 8, 9]
 |                                             ^
 |_____________________________________________|
 |_____________________________________________|
 |                                             |
 |                                             V
 |     arr.pop(0)                    [4, 5, 6, 7, 8, 9] 
 |     
 |     for i in arr                  [4, 5, 6, 7, 8, 9]
 |                                                ^
 |________________________________________________|
 |________________________________________________|
 |                                                |
 |                                                V
 |     arr.pop(0)                    [5, 6, 7, 8, 9] 
产出:

for index,i in enumerate(arr):
    if i in arr:
        print(index,i)
        arr.pop(0)
print arr

弹出会更改数组的长度,但迭代器的索引不会更新以反映这一点。

让我向您展示代码中发生的情况:

(0, 0)
(1, 2)
(2, 4)
(3, 6)
(4, 8)
[5, 6, 7, 8, 9]
让我们看看它在引擎盖下是如何工作的。首先,我们需要一个迭代器:

# Initial position
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# ^
# i

# Remove first
 [1, 2, 3, 4, 5, 6, 7, 8, 9]
# ^
# i

# Move next
 [1, 2, 3, 4, 5, 6, 7, 8, 9]
#    ^
#    i

# Remove first
 [2, 3, 4, 5, 6, 7, 8, 9]
#    ^
#    i

# Move next
 [2, 3, 4, 5, 6, 7, 8, 9]
#       ^
#       i

# And so on...

 [4, 5, 6, 7, 8, 9]
#             ^
#             i

# Remove first
 [5, 6, 7, 8, 9]
#             ^
#             i

# Move next
# Oops, the end of the list

# The result:

[5, 6, 7, 8, 9]
哇,我们从列表中得到了第一个元素!让我们看看,如果我们尝试弹出索引为零的元素,会发生什么情况:

In [32]: i = next(it)

In [33]: i
Out[33]: 0
好了,元素突然出现了。移动到下一个循环迭代:

# if i in arr:
#     print i
#     arr.pop(0)

In [34]: i in arr
Out[34]: True

In [35]: print i
0

In [36]: arr.pop(0)
Out[36]: 0

In [37]: arr
Out[37]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
嗯。。。似乎是对的,我们得到了第二个元素。让我们再来一次

In [38]: i = next(it)

In [39]: i
Out[39]: 2
让我们看看第三次迭代:

In [40]: i in arr
Out[40]: True

In [41]: print i
2

In [42]: arr.pop(0)
Out[42]: 1

In [43]: arr
Out[43]: [2, 3, 4, 5, 6, 7, 8, 9]
我想,现在很清楚,这个循环将有5次迭代。在每次迭代中,您将删除第一个元素。因此,在迭代时将跳过奇数元素

In [40]: i in arr
Out[40]: True

In [41]: print i
2

In [42]: arr.pop(0)
Out[42]: 1

In [43]: arr
Out[43]: [2, 3, 4, 5, 6, 7, 8, 9]
In [44]: i = next(it)

In [45]: i
Out[45]: 4