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