你竟任着剛硬不悔改的心,爲本身積蓄忿怒,以至神震怒,顯他公義審判的日子來到。他必照各人的行爲報應各人。凡恆心行善,尋求榮耀、尊貴和不能朽壞之福的,就以永生報應他們;唯有結黨不順從真理,反順從不義的,就以忿怒、惱恨報應他們。(ROMANS 2:7-8)
迭代
跟一些比較牛X的程序員交流,常常聽到他們嘴裏冒出一個不標準的英文單詞,而loop、iterate、traversal和recursion若是不在其內,總以爲他還不夠牛X。當讓,真正牛X的絕對不會這麼說的,他們只是說「循環、迭代、遍歷、遞歸」,而後再問「這個你懂嗎?」。哦,這就是真正牛X的程序員。不過,他也僅僅是牛X罷了,還不是大神。大神程序員是什麼樣兒呢?他是掃地僧,大隱隱於市。
循環(loop),指的是在知足條件的狀況下,重複執行同一段代碼。好比,while語句。
迭代(iterate),指的是按照某種順序逐個訪問列表中的每一項。好比,for語句。
遞歸(recursion),指的是一個函數不斷調用自身的行爲。好比,以編程方式輸出著名的斐波納契數列。
遍歷(traversal),指的是按照必定的規則訪問樹形結構中的每一個節點,並且每一個節點都只訪問一次。
對於這四個聽起來高深莫測的詞彙,其實前面,已經涉及到了一個——循環(loop),本節主要介紹一下迭代(iterate),看官在網上google,就會發現,對於迭代和循環、遞歸之間的比較的文章很多,分別從不一樣角度將它們進行了對比。這裏暫不比較,先搞明白python中的迭代。
固然,迭代的話題若是要提及來,會很長,本着按部就班的原則,這裏介紹比較初級的。
逐個訪問
在python中,訪問對象中每一個元素,能夠這麼作:(例如一個list)
>>> lst
['q', 'i', 'w', 's', 'i', 'r']
>>> for i in lst:
... print i,
...
q i w s i r
除了這種方法,還能夠這樣:
>>> lst_iter = iter(lst) #對原來的list實施了一個iter()
>>> lst_iter.next() #要不厭其煩地一個一個手動訪問
'q'
>>> lst_iter.next()
'i'
>>> lst_iter.next()
'w'
>>> lst_iter.next()
's'
>>> lst_iter.next()
'i'
>>> lst_iter.next()
'r'
>>> lst_iter.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
iter()是一個內建函數,其含義是:
上面的next()就是要得到下一個元素,可是作爲一名優秀的程序員,最佳品質就是「懶惰」,固然不能這樣一個一個地敲啦,因而就:
>>> 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()
...
q #果真自動化地讀取了
i
w
s
i
r
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以外,還有別的能夠稱做迭代工具。
那麼,剛纔介紹的iter()的功能呢?它與next()配合使用,也是實現上述迭代工具的做用。
在python中,甚至在其它的語言中,迭代這塊的說法比較亂,主要是名詞亂,剛纔咱們說,那些可以實現迭代的東西,稱之爲迭代工具,就是這些迭代工具,很多程序員都喜歡叫作迭代器。固然,這都是漢語翻譯,英語就是iterator。
看官看上面的全部例子會發現,若是用for來迭代,當到末尾的時候,就自動結束了,不會報錯。若是用iter()...next()迭代,當最後一個完成以後,它不會自動結束,還要向下繼續,可是後面沒有元素了,因而就報一個稱之爲StopIteration的錯誤(這個錯誤的名字叫作:中止迭代,這哪裏是報錯,分明是警告)。
看官還要關注iter()...next()迭代的一個特色。當迭代對象lst_iter被迭代結束,即每一個元素都讀取了一遍以後,指針就移動到了最後一個元素的後面。若是再訪問,指針並無自動返回到首位置,而是仍然停留在末位置,因此報StopIteration,想要再開始,須要從新載入迭代對象。因此,當我在上面從新進行迭代對象賦值以後,又能夠繼續了。這在for等類型的迭代工具中是沒有的。
文件迭代器
如今有一個文件,名稱:208.txt,其內容以下:
Learn python with qiwsir. There is free python course. The website is:

http://qiwsir.github.io Its language is Chinese.
用迭代器來操做這個文件,咱們在前面講述文件有關知識的時候已經作過了,無非就是:
>>> f = open("208.txt")
>>> f.readline() #讀第一行
'Learn python with qiwsir.\n'
>>> f.readline() #讀第二行
'There is free python course.\n'
>>> f.readline() #讀第三行
'The website is:\n'
>>> f.readline() #讀第四行
'

http://qiwsir.github.io\n'
>>> f.readline() #讀第五行,也就是這真在讀完最後一行以後,到了此行的後面
'Its language is Chinese.\n'
>>> f.readline() #無內容了,可是不報錯,返回空。
''
以上演示的是用readline()一行一行地讀。固然,在實際操做中,咱們是絕對不能這樣作的,必定要讓它自動進行,比較經常使用的方法是:
>>> for line in f: #這個操做是緊接着上面的操做進行的,請看官主要觀察
... print line, #沒有打印出任何東西
...
這段代碼之所沒有打印出東西來,是由於通過前面的迭代,指針已經移到了最後了。這就是迭代的一個特色,要當心指針的位置。
>>> f = open("208.txt") #從頭再來
>>> for line in f:
... print line,
...
Learn python with qiwsir.
There is free python course.
The website is:
http://qiwsir.github.io
Its language is Chinese.
這種方法是讀取文件經常使用的。另一個readlines()也能夠。可是,須要有一些當心的地方,看官若是想不起來當心什麼,能夠在將關於文件的課程複習一邊。
上面過程用next()也可以讀取。
>>> f = open("208.txt")
>>> f.next()
'Learn python with qiwsir.\n'
>>> f.next()
'There is free python course.\n'
>>> f.next()
'The website is:\n'
>>> f.next()
'

http://qiwsir.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偷偷地替咱們幹了,到這裏,列位是否是應該給for取另一個名字:它叫雷鋒。
還有,列表解析也可以作爲迭代工具,在研究列表的時候,看官想必已經清楚了。那麼對文件,是否能夠用?試一試:
>>> [ line for line in open('208.txt') ]
['Learn python with qiwsir.\n', 'There is free python course.\n', 'The website is:\n', '

http://qiwsir.github.io\n', 'Its language is Chinese.\n']
至此,看官難道還不爲列表解析所折服嗎?真的很強大,又強又大呀。
其實,迭代器遠遠不止上述這麼簡單,下面咱們隨便列舉一些,在python中還能夠這樣獲得迭代對象中的元素。
>>> list(open('208.txt'))
['Learn python with qiwsir.\n', 'There is free python course.\n', 'The website is:\n', '

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

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

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

http://qiwsir.github.io\n'
>>> e
'Its language is Chinese.\n' 上述方式,在編程實踐中不必定用得上,只是向看官展現一下,而且看官要明白,能夠這麼作,不是非要這麼作。 補充一下,字典也能夠迭代,看官本身不妨摸索一下(其實前面已經用for迭代過了,此次請摸索一下用iter()...next()手動一步一步迭代)。