標籤:

Python的for使用問題?

t = [i for i in range(5)]

for i in t:

····print i

····if t.index(i) == 0:

········t.remove(i)

題主的理解是,它會遍歷這個t並列印每一個元素,並且刪除第0個元素,所以它將列印0,1,2,3,4。但事實上刪掉第0個元素後,for直接跳到了第2個元素,第1個元素沒有被遍歷,輸出了0,2,3,4。新手遇到這個情況,很是不解,請大神點撥。


槽點好多啊……依次吐槽……

1. 從print的樣式來看,這是py2,那麼py2的range就已經產生了一個list,這時再用列表展開來建個t完全是沒有意義。

2. list的index方法的作用是返回list中第一個與參數相等的元素下標,而remove方法的作用是刪除第一個參數相等的項,於是綜合起來其實是:如果i的下標是0,則刪除list中第一個i。雖說沒什麼錯,但是index是O(n)的,remove也是,於是莫名地時間複雜度上升一階。

3. for loop是容器/生成器迭代,換到C++11里你敢這麼玩分分鐘給你個錯誤。Python不報錯還真是對不住了。如果感興趣可以翻看list的源碼中iter部分。當把一個list取來迭代器做循環時,實際的迭代原則是根據下標。那麼你的代碼流程大概是這樣:輸出t[0]----刪除0---輸出t[1]---輸出t[2]……

但是當你刪除0之後,t發生了改變,此時t[0]已經變成了1,而迭代器並不知情,下一輪循環就開始輸出t[1],也就是2了,跳過了1。


前面 Coldwings 已經把原理講明白了

我給你推薦個網站吧,可視化 Python 編程,只要不 import 包,大多數代碼執行過程中引用和內存的變化都可以用圖形化方式給你表現出來 (類似於簡化版的 IDE 單步調試 )

Visualize Python, Java, JavaScript, TypeScript, and Ruby code execution

紅色為待執行片段,你的代碼出問題就在這兩行之間,右側清晰列出了執行代碼後列表 t 的變化過程


新手最容易犯的一個錯誤,邊遍歷list,邊修改了結構。


一句話就是,當你刪掉了一個成員之後,他後面所有的成員當然就都前移了一格,導致你取下一個位置的時候取到的是下下個,因為你要的那個「下一個」已經佔用了你剛刪的那個位置。


迭代器迭代過程中不允許增刪。


下次再有不會的用 http://pythontutor.com看看就懂了。


我用專欄里的一篇文章來答題。

專欄鏈接:給妹子講python,歡迎大家關注,提意見!

系統的來看看for循環的使用

for循環更加通用,他是一個通用的序列迭代工具,可以遍歷任何有序的序列對象內的元素。例如之前介紹過的:字元串、列表、元組等,以及其他一些內置的可以用來迭代的對象(到時候專門展開)。

回顧幾個例子,列表、字元串、元組的遍歷

for x in [1,2,3,4]:
print(x, end=" ")

1 2 3 4

for x in "hello":
print(x, end=" ")

h e l l o

for x in ("i", "am", "a", "teacher"):
print(x,end=" ")

i am a teacher

T = [(1, 2), (3, 4), (5, 6)]
for (a, b) in T:
print(a,b)

1 2
3 4
5 6

這裡再單獨說說另外兩種特殊的內置類型對象,一個是字典、一個是文件。

字典的遍歷

字典的遍歷這裡單獨說說,相比於上面幾個序列類型,字典的特殊之處在於他內部的對象不是有序的。

但是他也能通過for循環來遍歷,常見的是通過值來遍歷,還有一種是通過鍵值對的元組來遍歷

D = {"a":1, "b":2, "c":3}
for key in D:
print(key, "---&>", D[key])

b ---&> 2
c ---&> 3
a ---&> 1

D = {"a": 1, "b": 2, "c": 3}
for (key, value) in D.items():
print(key, "---&>", value)

a ---&> 1
c ---&> 3
b ---&> 2

文件的遍歷

因為文件保存了很多字元和行,因此也是循環常見的典型使用案例,最原始的方法可以調用文件對象的read方法,把文件內容一次性載入至字元串對象

file = open("myfile.txt", "r")
print(file.read())

hello text file
goodbyt text file
Hahahahah

那麼如果想逐行讀取文本文件呢?for循環是最易於編寫及執行最快的選擇,這裡有兩種方法,

for line in open("myfile.txt","r").readlines():
print(line, end="")

for line in open("myfile.txt","r"):
print(line, end="")

hello text file
goodbyt text file
Hahahahah

這兩種方法的運行結果是一樣的,表面差別不大,但實際上有很大的區別:

第一種方法通過readlines方法,會首先一次性把文件載入到行字元串列表中,然後再對這個字元串列表進行迭代;

而第二種方法運行的原理則有所不同,他並非一次性將全部的文件內容載入到內存中,而是在迭代的時候,循環到了哪一行才將哪一行讀入到內存。這裡涉及到一個新的概念----迭代器(open函數返回的那個就是文件迭代器),後面再著重系統介紹。

現在我們只需要知道,第二種方法是文本文件讀取的最佳選擇,它簡單、且對任意大小的文件都有效,因為他不會一次性把整個文件都載入到內存中,相反第一種方法存在內存壓力過大的問題。


帶著問題去學,學了解決實際問題,逐漸就離不開他了。學點面向對象的思想就可以學python,沒必要先學。


推薦閱讀:

怎麼樣算是學會一門編程語言?
你們開始是如何學習編程的?
看代碼千行,不如手寫一行,是否在理?為何?
通過什麼可以了解一個程序員/黑客的真實水平?
Unix/Linux socket 編程的一個問題?

TAG:Python | 編程 |