迭代器
迭代器協(xié)議:
對象需要提供next()方法,它要么返回迭代中的下一項,要么就引起一個StopIteration異常,以終止迭代。
可迭代對象:
實現(xiàn)了迭代器協(xié)議對象。list、tuple、dict都是Iterable(可迭代對象),但不是iteration(迭代器對象)。但可以使用內(nèi)建函數(shù)iter(),把這些都變成iteration(迭代器對象)。
為什么在python中,文件還可以使用for循環(huán)進行遍歷呢?這是因為,在python中,文件對象實現(xiàn)了迭代器協(xié)議,for循環(huán)并不知道它遍歷的是一個文件對象,它只管使用迭代器協(xié)議訪問對象即可。正是由于python的文件對象實現(xiàn)了迭代器協(xié)議,我們才得以使用如此方便的方式訪問文件,如下所示:
>>>hasattr(open(__file__),'__iter__')
True
為什么list、dict、str等數(shù)據(jù)類型不是Iterator?
1.Python的Iterator對象表示的是一個數(shù)據(jù)流,雖然這個數(shù)據(jù)流看做是一個有序序列,但是元素的獲得只能通過next(),因為Iterator的計算是惰性的,只有在需要返回下一個數(shù)據(jù)時它才會計算。
2.而list、dict、str等數(shù)據(jù)類型,提供了對元素更加方便的操作,可以直接獲取元素,提前知道序列的長度。
3.但是,iterator也有好處,它可以表示一個無限大的數(shù)據(jù)流,例如全體自然數(shù)。而使用list是永遠不可能存儲全體自然數(shù)的。
生成器
1.兩種產(chǎn)生方式:
①生成器函數(shù):
常規(guī)函數(shù)定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數(shù)的狀態(tài),以便下次從它離開的地方繼續(xù)執(zhí)行
defhello():
? ? ?for i in ?range(3):
? ? ? ? ? yield i*i
for i ?in ?hello():
? ? print ?i
注意:在函數(shù)hello被調(diào)用的時候,返回的是生成器;只有在第一次next()的時候才會從頭執(zhí)行函數(shù)直到碰到y(tǒng)ield,之后繼續(xù)從上次yield這一句之后繼續(xù)執(zhí)行,直到不滿足條件,沒有值可以獲得。
②生成器表達式:
類似于列表推導,只不過是把一對大括號[]變換為一對小括號()。但是,生成器表達式是按需產(chǎn)生一個生成器結果對象,要想拿到每一個元素,就需要循環(huán)遍歷。
>>>gen = (i*i for i in range(3))
2.好處
①延遲操作。也就是在需要的時候才產(chǎn)生結果,不是立即產(chǎn)生結果。
例如:
print sum( [ i for i in range(10000000000) ?])
print sum( i ? for i in range(10000000000) ? )
第一種方式很容易出現(xiàn)電腦卡死,因為會一次性將list中的內(nèi)容加載到內(nèi)存中
②簡化代碼,提高代碼可讀性
def ?hello(text):
? ? ? ?result = []
? ? ? ?if ? ?text:
? ? ? ? ? ? ? result.append(0)
? ? ? ?for ?index,letter in enumerate(text,1):
? ? ? ? ? ? ? if ?letter ==' ':
? ? ? ? ? ? ? ? ? ? result.append(index)
? ? ? ?return ? result
def ?hello(text):
? ? ? ? if ? ?text:
? ? ? ? ? ? ? ?yield0
? ? ? ? for ?index,letter ? ?in ?enumerate(text,1):
? ? ? ? ? ? ? if ? ?letter ==' ':
? ? ? ? ? ? ? ? ? ? yield index
注意:不使用生成器的時候,對于每次結果,我們首先看到的是result.append(index),其次,才是index。也就是說,我們每次看到的是一個列表的append操作,只是append的是我們想要的結果。使用生成器的時候,直接yield index,少了列表append操作的干擾,我們一眼就能夠看出,代碼是要返回index。
3.注意事項
生成器只能遍歷一次,第二次遍歷的時候返回空
4.深入理解
①與函數(shù)比較:生成器函數(shù)和常規(guī)函數(shù)幾乎是一樣的。它們都是使用def語句進行定義,差別在于,生成器使用yield語句返回一個值,而常規(guī)函數(shù)使用return語句返回一個值。
②與迭代器關系:會自動實現(xiàn)迭代器協(xié)議,以便應用到迭代背景中(如for循環(huán),sum函數(shù))。由于生成器自動實現(xiàn)了迭代器協(xié)議,所以,我們可以調(diào)用它的next方法,并且,在沒有值可以返回的時候,生成器自動產(chǎn)生StopIteration異常。生成器是一種迭代器
③掛起狀態(tài):生成器使用yield語句返回一個值。yield語句掛起該生成器函數(shù)的狀態(tài),保留足夠的信息,以便之后從它離開的地方繼續(xù)執(zhí)行
5.應用場景:
1.你不需要重復讀這些值
2.你可能有海量的子節(jié)點,但是不希望將所有節(jié)點放入內(nèi)存