天天看點

python 疊代疊代

疊代

循環(loop),指的是在滿足條件的情況下,重複執行同一段代碼。比如,while語句。

疊代(iterate),指的是按照某種順序逐個通路清單中的每一項。比如,for語句。

遞歸(recursion),指的是一個函數不斷調用自身的行為。比如,以程式設計方式輸出著名的斐波納契數列。

周遊(traversal),指的是按照一定的規則通路樹形結構中的每個節點,而且每個節點都隻通路一次。

對于這四個聽起來高深莫測的詞彙,在教程中,已經涉及到了一個——循環(loop),本經主要介紹一下疊代(iterate),看官在網上google,就會發現,對于疊代和循環、遞歸之間的比較的文章不少,分别從不同角度将它們進行了對比。這裡暫不比較,先搞明白python中的疊代。

逐個通路

在python中,通路對象中每個元素,可以這麼做:(例如一個list)

>>> lst
['h', 'i', 'e', 'k', 'a', 'y']
>>> for i in lst:
...     print i,
... 
h i e k a y
除了這種方法,還可以這樣:

>>> lst_iter = iter(lst)    #對原來的list實施了一個iter()
>>> lst_iter.next()         #要不厭其煩地一個一個手動通路
'h'
>>> lst_iter.next()
'i'
>>> lst_iter.next()
'y'
>>> lst_iter.next()
'k'
>>> lst_iter.next()
'a'
>>> lst_iter.next()
'y'
>>> lst_iter.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration           

循環:

>>> while True:
...     print lst_iter.next()
... 
Traceback (most recent call last):      #居然報錯,而且錯誤跟前面一樣?什麼原因
  File "<stdin>", line 2, in <module>
StopIteration

>>> lst_iter = iter(lst)                #那就再寫一遍,上面的錯誤暫且擱置,回頭在研究
>>> while True:
...     print lst_iter.next()
... 
h                                       #果然自動化地讀取了
i
e
k
a
y
Traceback (most recent call last):      #讀取到最後一個之後,報錯,停止循環
  File "<stdin>", line 2, in <module>
StopIteration
>>>            

首先了解一下上面用到的那個内置函數:iter(),官方文檔中有這樣一段話描述之:

iter(o[, sentinel])

Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, o must be a collection object which supports the iteration protocol (the iter() method), or it must support the sequence protocol (the getitem() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

傳回值是一個疊代器對象

參數需要是一個符合疊代協定的對象或者是一個序列對象

next()配合與之使用

什麼是“可疊代的對象”呢?一般,我們常常将哪些能夠用for來一個一個讀取元素的對象,就稱之為可疊代的對象。那麼for也就被稱之為疊代工具。所謂疊代工具,就是能夠按照一定順序掃描疊代對象的每個元素(按照從左到右的順序),顯然,除了for之外,還有别的可以稱作疊代工具,比如清單解析,in來判斷某元素是否屬于序列對象等。

那麼,剛才介紹的iter()的功能呢?它與next()配合使用,也是實作上述疊代工具的作用。在python中,甚至在其它的語言中,疊代這塊的說法比較亂,主要是名詞亂,剛才我們說,那些能夠實作疊代的東西,稱之為疊代工具,就是這些疊代工具,不少程式員都喜歡叫做疊代器。當然,這都是漢語翻譯,英語就是iterator。

上面的所有例子會發現,如果用for來疊代,當到末尾的時候,就自動結束了,不會報錯。如果用iter()...next()疊代,當最後一個完成之後,它不會自動結束,還要向下繼續,但是後面沒有元素了,于是就報一個稱之為StopIteration的錯誤(這個錯誤的名字叫做:停止疊代,這哪裡是報錯,分明是警告)。

看官還要關注iter()...next()疊代的一個特點。當疊代對象lst_iter被疊代結束,即每個元素都讀取一邊之後,指針就移動到了最後一個元素的後面。如果再通路,指針并沒有自動傳回到首位置,而是仍然停留在末位置,是以報StopIteration,想要再開始,需要重新再入疊代對象。是以,列位就看到,當我在上面重新進行疊代對象指派之後,又可以繼續了。這在for等類型的疊代工具中是沒有的。

檔案疊代器

現在有一個檔案,名稱:iterfile.txt,其内容如下:

Learn python with hiekay.

There is free python course.

The website is:

http://hiekay.github.io

Its language is Chinese.

用疊代器來操作這個檔案,我們在前面講述檔案有關知識的時候已經做過了,無非就是:

>>> f = open("iterfile.txt")
>>> f.readline()        #讀第一行
'Learn python with hiekay.\n'
>>> f.readline()        #讀第二行
'There is free python course.\n'
>>> f.readline()        #讀第三行
'The website is:\n'
>>> f.readline()        #讀第四行
'http://hiekay.github.io\n'
>>> f.readline()        #讀第五行,也就是這真在讀完最後一行之後,到了此行的後面
'Its language is Chinese.\n'
>>> f.readline()        #無内容了,但是不報錯,傳回空。
''           

以上示範的是用readline()一行一行地讀。當然,在實際操作中,我們是絕對不能這樣做的,一定要讓它自動進行,比較常用的方法是:

>>> for line in f:     #這個操作是緊接着上面的操作進行的,請看官主要觀察
...     print line,    #沒有列印出任何東西 
...            

這段代碼之所沒有列印出東西來,是因為經過前面的疊代,指針已經移到了最後了。這就是疊代的一個特點,要小心指針的位置。

>>> f = open("iterfile.txt")     #從頭再來
>>> for line in f:
...     print line,
... 
Learn python with hiekay.
There is free python course.
The website is:
http://hiekay.github.io
Its language is Chinese.           

這種方法是讀取檔案常用的。另外一個readlines()也可以。

上面過程用next()也能夠讀取。

>>> f = open("iterfile.txt")
>>> f.next()
'Learn python with hiekay.\n'
>>> f.next()
'There is free python course.\n'
>>> f.next()
'The website is:\n'
>>> f.next()
'http://hiekay.github.io\n'
>>> f.next()
'Its language is Chinese.\n'
>>> f.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration           

如果用next(),就可以直接讀取每行的内容。這說明檔案是天然的可疊代對象,不需要用iter()轉換了。

再有,我們用for來實作疊代,在本質上,就是自動調用next(),隻不過這個工作,已經讓for偷偷地替我們幹了。

前面提到了,清單解析也能夠做為疊代工具,在研究清單的時候,看官想必已經清楚了。那麼對檔案,是否可以用?試一試:

>>> [ line for line in open('iterfile.txt') ]
['Learn python with hiekay.\n', 'There is free python course.\n', 'The website is:\n', 'http://hiekay.github.io\n', 'Its language is Chinese.\n']           

至此, 清單解析 真的很強大。

其實,疊代器遠遠不止上述這麼簡單,下面我們随便列舉一些,在python中還可以這樣得到疊代對象中的元素。

>>> list(open('iterfile.txt'))
['Learn python with hiekay.\n', 'There is free python course.\n', 'The website is:\n', 'http://hiekay.github.io\n', 'Its language is Chinese.\n']

>>> tuple(open('iterfile.txt'))
('Learn python with hiekay.\n', 'There is free python course.\n', 'The website is:\n', 'http://hiekay.github.io\n', 'Its language is Chinese.\n')

>>> "$$$".join(open('iterfile.txt'))
'Learn python with hiekay.\n$$$There is free python course.\n$$$The website is:\n$$$http://hiekay.github.io\n$$$Its language is Chinese.\n'

>>> a,b,c,d,e = open("iterfile.txt")
>>> a
'Learn python with hiekay.\n'
>>> b
'There is free python course.\n'
>>> c
'The website is:\n'
>>> d
'http://hiekay.github.io\n'
>>> e
'Its language is Chinese.\n'           

上述方式,在程式設計實踐中不一定用得上 。

補充一下,字典也可以疊代,可以自己不妨摸索一下(其實前面已經用for疊代過了,這次請摸索一下用iter()...next()手動一步一步疊代)。