為什麼python中不建議在for循環中修改列表?
Python中,為什麼說for是一種遍歷列表的有效方式,但是不建議在for循環中修改列表,否則將導致python難以跟蹤其中的元素?python會在for循環中跟蹤列表的元素嗎?跟蹤做什麼?為什麼又建議在while循環中修改列表,是因為while循環不會跟蹤列表元素嗎?初學python,勿噴
直接上代碼演示。
對這個list進行操作。a = [1, 2, 3, 4, 5, 6]
for i in range(len(a)):
if a[i] == 3:
a[i] = 4
或者這樣
for i, v in enumerate(a):
if v == 3:
a[i] = 4
a = [1, 2, 4, 4, 5]
好像用for循環完成得挺順利的,但是列表的修改,不僅限於對值得修改,還有插入和刪除。
接著上一步,我們現在要嘗試刪除裡面所有值為4的元素。for i, v in enumerate(a):
if v == 4:
del a[i]
a = [1, 2, 4, 5]
for i in range(len(a)):
if a[i] == 4:
del a[i]
Traceback (most recent call last):
File "&
IndexError: list index out of range
由於在遍歷的過程中,刪除了其中一個元素,導致後面的元素整體前移,導致有個元素成了漏網之魚。同樣的,在遍歷過程中,使用插入操作,也會導致類似的錯誤。這也就是問題里說的無法「跟蹤」元素。
如果使用while,則可以在面對這樣情況的時候靈活應對。同樣是上面那個例子。i = 0
while i &< len(a):
if a[i] == 4:
del a[i]
else:
i += 1
樓上@mouser 已經從iterator的角度解釋清楚了這個問題為何會出現:在修改過程中,原list的長度可能會發生變化,導致for-in循環的遍歷不夠「到位」(不越界、不漏值)。
小白來補充一點如何解決這個問題吧~
As the Python tutorial (https://docs.python.org/3/tutorial/controlflow.html#for-statements) suggests, "If you need to modify the sequence you are iterating over while inside the loop (for example to duplicate selected items), it is recommended that you first make a copy." You can copy a list by calling the list constructor or slicing the list from the beginning to the end.
——UCB CS 61A Sp17 第三次project
翻譯過來:把原有的list複製一下,遍歷拷貝的list、但修改原有的list。
比如Python的list循環遍歷中,刪除數據的正確方法 - bananaplan - 博客園 提供了一個例子:
num_list = [1, 2, 3, 4, 5]
print(num_list)
for item in num_list[:]:
if item == 2: num_list.remove(item)
else:
print(item)
print(num_list)
(附)複製列表的方法:
lst = [1,2,3]
lst1 = lst[:] # one way
lst2 = list(lst) # another
?(^?^*)啦啦
本質上,這是個 for xxx in 可迭代對象: 的問題
拿這個舉例
for i in range(5):
在程序第一次運行到這句的時候,
python會自動去調用range(5)對象的__iter__()方法,返回一個range_iterator對象
再由這個range_iterator對象不斷調用其__next__()方法,直到捕獲異常StopIteration為止
完成迭代
換句話說,當執行這個for語句的時候,迭代次數就已經被in後面的可迭代對象確定下來了
至於通過__next__()方法返回的值是怎麼和i產生關係的,好像不屬於這個問題
當已經被確定了迭代(循環)次數後
在列表沒有贈刪元素時,當然不會有越界的危險
但一旦在迭代過程中pop()或者append()元素後
前者越界
後者漏值
「扁平結構比嵌套結構更好」 – 《Python之禪》
比如 list(map(lambda x:4 if x==3 else x,a))
如果一定要用for:
a = [1, 2, 3, 4, 5, 6]
3變成4
[4 if x==3 else x for x in a]
b = [1, 2, 4, 4, 5, 6]
刪除4
[x for x in b if x != 4]
也是可以的。。
推薦閱讀:
※Python技術分享的亂象
※Python 黑帽編程大綱(變化中)
※Python爬蟲實戰六之抓取愛問知識人問題並保存至資料庫
TAG:Python |