代碼迴路彈出一個元素髮生了什麼:當在名單
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]
爲什麼是這樣的結果?應該不是[]
?
更新序列時迭代有一些意想不到的結果,這就是爲什麼它從不被推薦。下圖描述了可變i
如何改變你每次迭代而從列表中
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]
建議您在迭代序列(或映射)時不要修改序列(或映射)。它會混淆interal指針。
例如,下面的代碼將永遠不會結束。
arr = [1,2,3]
for i in arr:
print i
arr.append(i)
注:有序時,正在由 環改性(這僅可導致產生可變的序列,即列表)一個微妙。一個 內部計數器用於跟蹤下一個使用的項目,並且 在每次迭代時遞增。當此計數器達到 時,循環終止的序列長度。 這意味着如果 套件從序列中刪除當前(或前一個)項目,則會跳過下一項目(因爲它獲取已處理的當前項目 的索引)。同樣,如果套件在當前項目之前的序列中插入 項目,則當前項目將在下次通過循環時再次處理 。這可能會導致可以通過使使用的 片的整個序列的臨時副本,比如避免討厭的 錯誤,
for x in a[:]: if x < 0: a.remove(x)
你whanted是顯然的:
for i in range(len(arr)):
arr.pop(0)
因爲,正如@falsetru提到的那樣,不建議在迭代過程中更改序列,但在本例中,for循環基於一個常量值,即長度爲arr
。每個pop()
將刪除第一個元素,並且列表將逐漸清空。
它更容易看到最新加入的枚舉去上彈出時間:
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]
Popping更改數組的長度,但迭代器的索引未更新以反映此情況。
讓我告訴你的代碼會發生什麼:
# 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]
讓我們來看看它是如何引擎蓋下工作。首先,我們需要一個迭代器:
# for i in arr:
In [30]: it = iter(arr)
In [31]: it
Out[31]: <listiterator at 0x130f9d0>
我們將稱之爲next(it)
,直到它上升一個StopIteration
例外。所以,讓我們來做:
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]
讓我們在第三次迭代看到:
In [44]: i = next(it)
In [45]: i
Out[45]: 4
我想,它現在是明確的,即循環將有5次迭代。在每次迭代中,您將刪除第一個元素。而且,正因爲如此,您將在迭代時跳過奇怪的元素。