迭代是數(shù)據(jù)處理的基石。掃描內(nèi)存中放不下的數(shù)據(jù)時(shí)沛婴,我們要找到一種惰性獲取數(shù)據(jù)項(xiàng)的方式吼畏,即按需一次獲取一個(gè)數(shù)據(jù)項(xiàng),這就是迭代器模式嘁灯。
在python語(yǔ)言內(nèi)部泻蚊,迭代器用于支持:
for 循環(huán)
構(gòu)建和擴(kuò)展集合類型
逐行遍歷文本文件
列表推導(dǎo)、字典推導(dǎo)和集合推導(dǎo)
元組拆包
調(diào)用函數(shù)時(shí)丑婿,使用*拆包實(shí)參
序列可迭代的原因:iter函數(shù)
解釋器需要迭代對(duì)象x時(shí)性雄,會(huì)自動(dòng)調(diào)用iter(x)
內(nèi)置的iter函數(shù)由以下作用。
1羹奉、檢查對(duì)象是否實(shí)現(xiàn)了__iter__方法秒旋,如果實(shí)現(xiàn)了就調(diào)用它,獲取一個(gè)迭代器诀拭。
2迁筛、如果沒(méi)有實(shí)現(xiàn)__iter__方法,但是實(shí)現(xiàn)了__getitem__方法炫加,python會(huì)創(chuàng)建一個(gè)迭代器瑰煎,嘗試按順序獲取元素。
3俗孝、如果嘗試失敗酒甸,python拋出TypeError異常,通常會(huì)提示“C object is not iterable”
可迭代的對(duì)象與迭代器的對(duì)比
可迭代的對(duì)象:
使用iter內(nèi)置函數(shù)可以獲取迭代器的對(duì)象赋铝。如果對(duì)象實(shí)現(xiàn)了能返回迭代器的__iter__方法插勤,那么對(duì)象就是可迭代的。序列都可以迭代,因?yàn)閷?shí)現(xiàn)了__getitem__方法农尖。
標(biāo)準(zhǔn)迭代器接口有兩個(gè)方法:
__next__:返回下一個(gè)可用的元素析恋,如果沒(méi)有元素了,則拋出StopIteration異常盛卡。
__iter__:返回self助隧,以便在應(yīng)該可迭代對(duì)象的地方使用迭代器。
迭代器:
迭代器時(shí)這樣的對(duì)象:實(shí)現(xiàn)了無(wú)參數(shù)的__next__方法滑沧,返回序列中的下一個(gè)元素并村,如果沒(méi)有元素了,那么拋出StopIteration異常滓技。python中的迭代器還實(shí)現(xiàn)了__iter__方法哩牍,因此迭代器也可以迭代。
典型的迭代器
下例中定義的Sentence類可以迭代令漂,因?yàn)樗鼘?shí)現(xiàn)了特殊的__iter__方法膝昆,構(gòu)建并返回一個(gè)SentenceIterator實(shí)例。
把Sentence變成迭代器:壞主意
可迭代的對(duì)象有個(gè)__iter__方法叠必,每次實(shí)例化一個(gè)新的迭代器荚孵,而迭代器要實(shí)現(xiàn)__next__方法,返回單個(gè)元素挠唆,此外還要實(shí)現(xiàn)__iter__方法处窥,返回迭代器本身嘱吗,因此玄组,迭代器可以迭代,但是可迭代對(duì)象不是迭代器谒麦。
可迭代的對(duì)象一定不能是自身的迭代器俄讹。也就是說(shuō),可迭代的對(duì)象必須實(shí)現(xiàn)__iter__方法绕德,但不能實(shí)現(xiàn)__next__方法患膛。
生成器函數(shù)
實(shí)現(xiàn)相同功能,但更符合python習(xí)慣的方式是耻蛇,用生成器函數(shù)代替SentenceIterator類踪蹬。
在上例中,迭代器其實(shí)是生成器對(duì)象臣咖,每次調(diào)用__iter__方法都會(huì)自動(dòng)創(chuàng)建跃捣,因?yàn)檫@里的__iter__方法是生成器函數(shù)。
生成器函數(shù)的工作原理
只要python函數(shù)的定義體中有yield關(guān)鍵字夺蛇,該函數(shù)就是生成器函數(shù)疚漆。調(diào)用生成器函數(shù)時(shí),會(huì)返回一個(gè)生成器對(duì)象,也就是說(shuō)娶聘,生成器函數(shù)是生成器工廠闻镶。
惰性實(shí)現(xiàn)
之前實(shí)現(xiàn)的幾版Sentence類都不具有惰性,因?yàn)開(kāi)_init__方法急迫地構(gòu)建好了文本中的單詞列表丸升,然后將其綁定到self.words屬性上铆农。這樣就得處理整個(gè)文本,列表使用的內(nèi)存量可能與文本本身一樣多狡耻。
re.finditer函數(shù)是re.findall函數(shù)的惰性版本顿涣,返回的不是列表,而是一個(gè)生成器酝豪。
生成器表達(dá)式
生成器表達(dá)式可以理解為列表推導(dǎo)的惰性版本:不會(huì)迫切地構(gòu)建列表涛碑,而是返回一個(gè)生成器,按需惰性生成元素孵淘。也就是說(shuō)蒲障,如果列表推導(dǎo)是制造列表的工廠,那么生成器表達(dá)式就是制造生成器的工廠瘫证。
下例先在列表推導(dǎo)中使用gen_AB生成器函數(shù)揉阎,然后在生成器表達(dá)式中使用
下例用生成器表達(dá)式實(shí)現(xiàn)Sentence類