改變你正在迭代的序列

for 迴圈遍歷序列,因此在迴圈內更改此序列可能會導致意外結果 (特別是在新增或刪除元素時):

alist = [0, 1, 2]
for index, value in enumerate(alist):
    alist.pop(index)
print(alist)
# Out: [1]

注意:list.pop() 用於從列表中刪除元素。

第二個元素未被刪除,因為迭代按順序遍歷索引。上面的迴圈迭代兩次,結果如下:

# Iteration #1
index = 0
alist = [0, 1, 2]
alist.pop(0) # removes '0'

# Iteration #2
index = 1
alist = [1, 2]
alist.pop(1) # removes '2'

# loop terminates, but alist is not empty:
alist = [1]

出現這個問題是因為索引在向增加索引的方向上迭代時發生變化。要避免此問題,你可以向後遍歷迴圈

alist = [1,2,3,4,5,6,7]
for index, item in reversed(list(enumerate(alist))):
    # delete all even items
    if item % 2 == 0:
        alist.pop(index)
print(alist)
# Out: [1, 3, 5, 7]

通過從最後開始迴圈遍歷,當項被刪除(或新增)時,它不會影響列表中較早的項的索引。因此,此示例將正確刪除所有甚至來自 alist 的專案。

將元素插入或追加到正在迭代的列表時會出現類似的問題,這會導致無限迴圈:

alist = [0, 1, 2]
for index, value in enumerate(alist):
    # break to avoid infinite loop:
    if index == 20:     
        break           
    alist.insert(index, 'a')
print(alist)
# Out (abbreviated): ['a', 'a', ..., 'a', 'a',  0,   1,   2]

如果沒有 break 條件,只要計算機記憶體不足並允許程式繼續執行,迴圈就會插入'a'。在這種情況下,通常首選建立一個新列表,並在迴圈原始列表時將項新增到新列表中。

使用 for 迴圈時,不能使用佔位符變數修改列表元素

alist = [1,2,3,4]
for item in alist:
    if item % 2 == 0:
        item = 'even'
print(alist)
# Out: [1,2,3,4]

在上面的示例中,更改 item 實際上不會更改原始列表中的任何內容。你需要使用列表索引(alist[2]),enumerate() 適用於此:

alist = [1,2,3,4]
for index, item in enumerate(alist):
    if item % 2 == 0:
        alist[index] = 'even'
print(alist)
# Out: [1, 'even', 3, 'even']

一個 while 迴圈可能會在某些情況下,更好的選擇:

如果要刪除列表中的所有專案

zlist = [0, 1, 2]
while zlist:
    print(zlist[0])
    zlist.pop(0)
print('After: zlist =', zlist)

# Out: 0
#      1
#      2
# After: zlist = []

雖然簡單地重置 zlist 將完成相同的結果;

zlist = []

以上示例也可以與 len() 結合使用以在某個點之後停止,或者刪除列表中除 x 之外的所有專案:

zlist = [0, 1, 2]
x = 1
while len(zlist) > x:
    print(zlist[0])
    zlist.pop(0)
print('After: zlist =', zlist)

# Out: 0
#      1
# After: zlist = [2]

或者在刪除滿足特定條件的元素時迴圈遍歷列表 (在這種情況下,刪除所有偶數元素):

zlist = [1,2,3,4,5]
i = 0
while i < len(zlist):
    if zlist[i] % 2 == 0:
        zlist.pop(i)
    else:
        i += 1
print(zlist)
# Out: [1, 3, 5]

請注意,刪除元素後不要增加 i。通過刪除 zlist[i] 中的元素,下一個專案的索引減少了 1,因此通過在下一次迭代中檢查 zlist[i] 具有相同的 i 值,你將正確檢查列表中的下一個專案。

考慮從列表中刪除不需要的專案的相反方法是將所需專案新增到新列表。以下示例是後一個 while 迴圈示例的替代示例:

zlist = [1,2,3,4,5]

z_temp = []
for item in zlist:
    if item % 2 != 0:
        z_temp.append(item)
zlist = z_temp
print(zlist)
# Out: [1, 3, 5]

在這裡,我們將所需的結果彙集到一個新的列表中。然後,我們可以選擇將臨時列表重新分配給原始變數。

通過這種思維趨勢,你可以呼叫 Python 最優雅和最強大的功能之一,列表推導,從而消除臨時列表,並與先前討論的就地列表/索引變異意識形態不同。

zlist = [1,2,3,4,5]
[item for item in zlist if item % 2 != 0]
# Out: [1, 3, 5]