什么是迭代
Wiki定義:是重復(fù)反饋過程的活動(dòng)阔涉,其目的是為了接近并到達(dá)所需的目標(biāo)或結(jié)果。
在程序中捷绒,迭代是一種遍歷集合元素的方式瑰排,我們可以通過索引值遞增來遍歷集合元素,而迭代是遍歷集合元素另一種方式暖侨。
下面是使用索引來進(jìn)行遍歷集合元素的方式:
val = [1,2,3,4,5]
for i in range(len(val)):
retVal = val[i]
這種方式在C++
中很常見椭住,在Python中我們可以用更簡(jiǎn)潔的語法來進(jìn)行遍歷,也就是迭代字逗。
三個(gè)關(guān)鍵字
說到迭代京郑,在Python里就會(huì)提到下面三個(gè)關(guān)鍵詞:
- Iterable(可迭代)
- iterator(迭代器)
- generator(生成器)
這三個(gè)關(guān)鍵字宅广,可能從一開始的某段代碼你就接觸到了,只是你沒有發(fā)覺些举,代碼是這樣的跟狱。
val = [1,2,3,4,5]
for i in val:
print i
上面這個(gè)for...in
,就是Python中迭代器的語法糖户魏。好了驶臊,現(xiàn)在你可能開始在想這個(gè)for做了什么事了,先把這個(gè)疑問放在心里叼丑,我們先一步步來解析上面的幾個(gè)關(guān)鍵字关翎。
Iterable 可迭代
先來看個(gè)反面教材,如果我們用for...in
語法糖去遍歷一個(gè)int會(huì)怎樣幢码?笤休??
intVal = 1024
for _ in intVal:
pass
>>>TypeError: 'int' object is not iterable
從上面的錯(cuò)誤可以看到症副,整數(shù)類型的對(duì)象不是可迭代的店雅,也就是說for..in
只適用于iterable對(duì)象,那么什么類型的對(duì)象才是iterable(可迭代)呢贞铣。
在Python中闹啦,實(shí)現(xiàn)了_iter_函數(shù)的類型都是可迭代的,例如list辕坝,tuple窍奋,dict等
可以用dir
函數(shù)查看一下是否存在協(xié)議函數(shù)__iter__
print '__iter__' in dir(dict)
print '__iter__' in dir(list)
print '__iter__' in dir(tuple)
>>>True
>>>True
>>>True
通過上面的方式我們可以判斷一個(gè)對(duì)象是不是可迭代的,當(dāng)然我們還有另外一種更接地氣的方法酱畅。
l = [1]
from collections import Iterable
print isinstance(l, Iterable) #注意這里只能用實(shí)例進(jìn)行判斷琳袄,而不能用list判斷
iterator 迭代器
對(duì)于一個(gè)可迭代的對(duì)象,我們需要借助迭代器來對(duì)其進(jìn)行迭代纺酸,那么我們?cè)趺床拍艿玫揭粋€(gè)迭代器呢窖逗?
iter()方法
通過使用iter
方法,我們可以得到一個(gè)迭代器餐蔬,記住碎紊,要傳入一個(gè)可迭代對(duì)象做為參數(shù):
l = [1]
o = iter(l)
print type(o)
>>><type 'listiterator'>
從上面的代碼可以看到,我們通過將一個(gè)可迭代對(duì)象傳給iter
方法得到了一個(gè)迭代器樊诺,那么有了這個(gè)迭代器之后仗考,我們應(yīng)該怎么迭代呢?
next()方法
調(diào)用迭代器的next
方法可以對(duì)元素進(jìn)行遍歷词爬,但是next
方法是不能無限使用的:
l = [1, 2, 3]
o = iter(l)
print o.next()
print o.next()
print o.next()
print o.next()
>>>1
>>>2
>>>3
>>>Traceback (most recent call last):
File "e:\Microsoft VS Code\TestFiles\test.py", line 63, in <module>
print o.next()
StopIteration
通過next
方法我們可以一個(gè)個(gè)的遍歷可迭代對(duì)象中的元素秃嗜,當(dāng)遍歷結(jié)束的時(shí)候,會(huì)引發(fā)異常StopIteration。
迭代器類
除了以上的方法痪寻,我們還可以構(gòu)造一個(gè)類來進(jìn)行迭代螺句,這個(gè)類需要實(shí)現(xiàn)next
和__iter__
方法,下面構(gòu)造了一個(gè)斐波那契數(shù)列:
class FabIteratorClass(object):
def __init__(self, max):
self.m_Max = max
self.m_Idx = 0
self.m_a = 0
self.m_b = 1
def __iter__(self):
return self
def next(self):
if self.m_Idx < self.m_Max:
ret = self.m_b
self.m_a, self.m_b = self.m_b, self.m_a + self.m_b
self.m_Idx += 1
return ret
raise StopIteration()
for val in FabIteratorClass(3):
print val
>>>1
>>>1
>>>2
所以橡类,作為一個(gè)迭代器蛇尚,他的特征如下:
- 擁有
__iter__
方法,或者由iter
方法返回 - 擁有
next
方法 - 會(huì)產(chǎn)生
StopIteration
異常
生成器
說到生成器顾画,那么一定會(huì)說到一個(gè)關(guān)鍵字yield
取劫,只要一個(gè)函數(shù)里出現(xiàn)了這個(gè)關(guān)鍵字,我們就把這個(gè)函數(shù)稱為生成器研侣,生成器是一種內(nèi)存友好的函數(shù)谱邪,例如平時(shí)用到的xrange
函數(shù),就是一個(gè)生成器庶诡,生成器不會(huì)把所有值預(yù)先生成惦银,而是在需要時(shí)才生成,是一種Lazy Evaluation的做法末誓。生成器也是迭代器的一種扯俱!
同樣是斐波那契數(shù)列,我們用生成器處理一下:
def fab(max):
idx = 0
a = 0
b = 1
while idx < max:
ret = b
a, b = b, a + b
idx += 1
yield ret
c = fab(5)
print type(c)
for val in c:
print val
>>><type 'generator'>
>>>1
>>>1
>>>2
>>>3
>>>5
總結(jié):
- 三者的繼承關(guān)系是這樣:generator--->Iterator--->Iterable
- 迭代器類型需要實(shí)現(xiàn)
__iter__
和next
方法喇澡,生成器是一種特殊的迭代器迅栅,內(nèi)部支持了生成器協(xié)議,不需要明確定義iter()和next()方法 - 迭代器一定是可迭代對(duì)象晴玖,但是可迭代對(duì)象不一定是迭代器