詳解Python之可迭代對(duì)象,迭代器和生成器
一、概念描述
可迭代對(duì)象就是可以迭代的對(duì)象,我們可以通過(guò)內(nèi)置的iter函數(shù)獲取其迭代器,可迭代對(duì)象內(nèi)部需要實(shí)現(xiàn)__iter__函數(shù)來(lái)返回其關(guān)聯(lián)的迭代器;
迭代器是負(fù)責(zé)具體數(shù)據(jù)的逐個(gè)遍歷的,其通過(guò)實(shí)現(xiàn)__next__函數(shù)得以逐個(gè)的訪問(wèn)關(guān)聯(lián)的數(shù)據(jù)元素;同時(shí)通過(guò)實(shí)現(xiàn)__iter__來(lái)實(shí)現(xiàn)對(duì)可迭代對(duì)象的兼容;
生成器是一種迭代器模式,其實(shí)現(xiàn)了數(shù)據(jù)的惰性生成,即只有使用的時(shí)候才會(huì)生成對(duì)應(yīng)的元素;
二、序列的可迭代性
python內(nèi)置的序列可以通過(guò)for進(jìn)行迭代,解釋器會(huì)調(diào)用iter函數(shù)獲取序列的迭代器,由于iter函數(shù)兼容序列實(shí)現(xiàn)的__getitem__,會(huì)自動(dòng)創(chuàng)建一個(gè)迭代器;
迭代器的
import re from dis import dis class WordAnalyzer: reg_word = re.compile('\w+') def __init__(self, text): self.words = self.__class__.reg_word.findall(text) def __getitem__(self, index): return self.words[index] def iter_word_analyzer(): wa = WordAnalyzer('this is mango word analyzer') print('start for wa') for w in wa: print(w) print('start while wa_iter') wa_iter = iter(wa) while True: try: print(next(wa_iter)) except StopIteration as e: break; iter_word_analyzer() dis(iter_word_analyzer) # start for wa # this # is # mango # word # analyzer # start while wa_iter # this # is # mango # word # analyzer # 15 0 LOAD_GLOBAL 0 (WordAnalyzer) # 2 LOAD_CONST 1 ('this is mango word analyzer') # 4 CALL_FUNCTION 1 # 6 STORE_FAST 0 (wa) # # 16 8 LOAD_GLOBAL 1 (print) # 10 LOAD_CONST 2 ('start for wa') # 12 CALL_FUNCTION 1 # 14 POP_TOP # # 17 16 LOAD_FAST 0 (wa) # 18 GET_ITER # >> 20 FOR_ITER 12 (to 34) # 22 STORE_FAST 1 (w) # # 18 24 LOAD_GLOBAL 1 (print) # 26 LOAD_FAST 1 (w) # 28 CALL_FUNCTION 1 # 30 POP_TOP # 32 JUMP_ABSOLUTE 20 # # 20 >> 34 LOAD_GLOBAL 1 (print) # 36 LOAD_CONST 3 ('start while wa_iter') # 38 CALL_FUNCTION 1 # 40 POP_TOP # # 21 42 LOAD_GLOBAL 2 (iter) # 44 LOAD_FAST 0 (wa) # 46 CALL_FUNCTION 1 # 48 STORE_FAST 2 (wa_iter) # # 23 >> 50 SETUP_FINALLY 16 (to 68) # # 24 52 LOAD_GLOBAL 1 (print) # 54 LOAD_GLOBAL 3 (next) # 56 LOAD_FAST 2 (wa_iter) # 58 CALL_FUNCTION 1 # 60 CALL_FUNCTION 1 # 62 POP_TOP # 64 POP_BLOCK # 66 JUMP_ABSOLUTE 50 # # 25 >> 68 DUP_TOP # 70 LOAD_GLOBAL 4 (StopIteration) # 72 JUMP_IF_NOT_EXC_MATCH 114 # 74 POP_TOP # 76 STORE_FAST 3 (e) # 78 POP_TOP # 80 SETUP_FINALLY 24 (to 106) # # 26 82 POP_BLOCK # 84 POP_EXCEPT # 86 LOAD_CONST 0 (None) # 88 STORE_FAST 3 (e) # 90 DELETE_FAST 3 (e) # 92 JUMP_ABSOLUTE 118 # 94 POP_BLOCK # 96 POP_EXCEPT # 98 LOAD_CONST 0 (None) # 100 STORE_FAST 3 (e) # 102 DELETE_FAST 3 (e) # 104 JUMP_ABSOLUTE 50 # >> 106 LOAD_CONST 0 (None) # 108 STORE_FAST 3 (e) # 110 DELETE_FAST 3 (e) # 112 RERAISE # >> 114 RERAISE # 116 JUMP_ABSOLUTE 50 # >> 118 LOAD_CONST 0 (None) # 120 RETURN_VALUE
三、經(jīng)典的迭代器模式
標(biāo)準(zhǔn)的迭代器需要實(shí)現(xiàn)兩個(gè)接口方法,一個(gè)可以獲取下一個(gè)元素的__next__方法和直接返回self的__iter__方法;
迭代器迭代完所有的元素的時(shí)候會(huì)拋出StopIteration異常,但是python內(nèi)置的for、列表推到、元組拆包等會(huì)自動(dòng)處理這個(gè)異常;
實(shí)現(xiàn)__iter__主要為了方便使用迭代器,這樣就可以最大限度的方便使用迭代器;
迭代器只能迭代一次,如果需要再次迭代就需要再次調(diào)用iter方法獲取新的迭代器,這就要求每個(gè)迭代器維護(hù)自己的內(nèi)部狀態(tài),即一個(gè)對(duì)象不能既是可迭代對(duì)象同時(shí)也是迭代器;
從經(jīng)典的面向?qū)ο笤O(shè)計(jì)模式來(lái)看,可迭代對(duì)象可以隨時(shí)生成自己關(guān)聯(lián)的迭代器,而迭代器負(fù)責(zé)具體的元素的迭代處理;
import re from dis import dis class WordAnalyzer: reg_word = re.compile('\w+') def __init__(self, text): self.words = self.__class__.reg_word.findall(text) def __iter__(self): return WordAnalyzerIterator(self.words) class WordAnalyzerIterator: def __init__(self, words): self.words = words self.index = 0 def __iter__(self): return self; def __next__(self): try: word = self.words[self.index] except IndexError: raise StopIteration() self.index +=1 return word def iter_word_analyzer(): wa = WordAnalyzer('this is mango word analyzer') print('start for wa') for w in wa: print(w) print('start while wa_iter') wa_iter = iter(wa) while True: try: print(next(wa_iter)) except StopIteration as e: break; iter_word_analyzer() # start for wa # this # is # mango # word # analyzer # start while wa_iter # this # is # mango # word # analyzer
四、生成器也是迭代器
生成器是調(diào)用生成器函數(shù)生成的,生成器函數(shù)是含有yield的工廠函數(shù);
生成器本身就是迭代器,其支持使用next函數(shù)遍歷生成器,同時(shí)遍歷完也會(huì)拋出StopIteration異常;
生成器執(zhí)行的時(shí)候會(huì)在yield語(yǔ)句的地方暫停,并返回yield右邊的表達(dá)式的值;
def gen_func(): print('first yield') yield 'first' print('second yield') yield 'second' print(gen_func) g = gen_func() print(g) for val in g: print(val) g = gen_func() print(next(g)) print(next(g)) print(next(g)) # <function gen_func at 0x7f1198175040> # <generator object gen_func at 0x7f1197fb6cf0> # first yield # first # second yield # second # first yield # first # second yield # second # StopIteration
我們可以將__iter__作為生成器函數(shù)
import re from dis import dis class WordAnalyzer: reg_word = re.compile('\w+') def __init__(self, text): self.words = self.__class__.reg_word.findall(text) def __iter__(self): for word in self.words: yield word def iter_word_analyzer(): wa = WordAnalyzer('this is mango word analyzer') print('start for wa') for w in wa: print(w) print('start while wa_iter') wa_iter = iter(wa) while True: try: print(next(wa_iter)) except StopIteration as e: break; iter_word_analyzer() # start for wa # this # is # mango # word # analyzer # start while wa_iter # this # is # mango # word # analyzer
五、實(shí)現(xiàn)惰性迭代器
迭代器的一大亮點(diǎn)就是通過(guò)__next__來(lái)實(shí)現(xiàn)逐個(gè)元素的遍歷,這個(gè)大數(shù)據(jù)容器的遍歷帶來(lái)了可能性;
我們以前的實(shí)現(xiàn)在初始化的時(shí)候,直接調(diào)用re.findall得到了所有的序列元素,并不是一個(gè)很好的實(shí)現(xiàn);我們可以通過(guò)re.finditer來(lái)在遍歷的時(shí)候得到數(shù)據(jù);
import re from dis import dis class WordAnalyzer: reg_word = re.compile('\w+') def __init__(self, text): # self.words = self.__class__.reg_word.findall(text) self.text = text def __iter__(self): g = self.__class__.reg_word.finditer(self.text) print(g) for match in g: yield match.group() def iter_word_analyzer(): wa = WordAnalyzer('this is mango word analyzer') print('start for wa') for w in wa: print(w) print('start while wa_iter') wa_iter = iter(wa) wa_iter1= iter(wa) while True: try: print(next(wa_iter)) except StopIteration as e: break; iter_word_analyzer() # start for wa # <callable_iterator object at 0x7feed103e040> # this # is # mango # word # analyzer # start while wa_iter # <callable_iterator object at 0x7feed103e040> # this # is # mango # word # analyzer
六、使用生成器表達(dá)式簡(jiǎn)化惰性迭代器
生成器表達(dá)式是生成器的聲明性定義,與列表推到的語(yǔ)法類似,只是生成元素是惰性的;
def gen_func(): print('first yield') yield 'first' print('second yield') yield 'second' l = [x for x in gen_func()] for x in l: print(x) print() ge = (x for x in gen_func()) print(ge) for x in ge: print(x) # first yield # second yield # first # second # # <generator object <genexpr> at 0x7f78ff5dfd60> # first yield # first # second yield # second
使用生成器表達(dá)式實(shí)現(xiàn)word analyzer
import re from dis import dis class WordAnalyzer: reg_word = re.compile('\w+') def __init__(self, text): # self.words = self.__class__.reg_word.findall(text) self.text = text def __iter__(self): # g = self.__class__.reg_word.finditer(self.text) # print(g) # for match in g: # yield match.group() ge = (match.group() for match in self.__class__.reg_word.finditer(self.text)) print(ge) return ge def iter_word_analyzer(): wa = WordAnalyzer('this is mango word analyzer') print('start for wa') for w in wa: print(w) print('start while wa_iter') wa_iter = iter(wa) while True: try: print(next(wa_iter)) except StopIteration as e: break; iter_word_analyzer() # start for wa # <generator object WordAnalyzer.__iter__.<locals>.<genexpr> at 0x7f4178189200> # this # is # mango # word # analyzer # start while wa_iter # <generator object WordAnalyzer.__iter__.<locals>.<genexpr> at 0x7f4178189200> # this # is # mango # word # analyzer
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
使用anaconda的pip安裝第三方python包的操作步驟
今天小編就為大家分享一篇使用anaconda的pip安裝第三方python包的操作步驟,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06簡(jiǎn)單的編程0基礎(chǔ)下Python入門指引
這篇文章主要介紹了簡(jiǎn)單的編程0基礎(chǔ)下Python入門指引,包括從各個(gè)系統(tǒng)的Python安裝和簡(jiǎn)單的語(yǔ)句知識(shí),需要的朋友可以參考下2015-04-04使用numpngw和matplotlib生成png動(dòng)畫的示例代碼
這篇文章主要介紹了使用numpngw和matplotlib生成png動(dòng)畫的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01解決Scrapy安裝錯(cuò)誤:Microsoft Visual C++ 14.0 is required...
下面小編就為大家?guī)?lái)一篇解決Scrapy安裝錯(cuò)誤:Microsoft Visual C++ 14.0 is required...的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10Python兩個(gè)整數(shù)相除得到浮點(diǎn)數(shù)值的方法
這篇文章主要介紹了Python兩個(gè)整數(shù)相除得到浮點(diǎn)數(shù)值的方法,本文直接給出代碼示例,需要的朋友可以參考下2015-03-03PyTorch中model.zero_grad()和optimizer.zero_grad()用法
這篇文章主要介紹了PyTorch中model.zero_grad()和optimizer.zero_grad()用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06Python SMTP發(fā)送郵件遇到的一些問(wèn)題及解決辦法
今天小編就為大家分享一篇關(guān)于Python SMTP發(fā)送郵件遇到的一些問(wèn)題及解決辦法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10Python輕量級(jí)web框架bottle使用方法解析
這篇文章主要介紹了Python輕量級(jí)web框架bottle使用方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06JupyterLab遠(yuǎn)程密碼訪問(wèn)實(shí)現(xiàn)
本文主要介紹了JupyterLab遠(yuǎn)程密碼訪問(wèn)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02Python的Flask項(xiàng)目中獲取請(qǐng)求用戶IP地址 addr問(wèn)題
這篇文章主要介紹了Python的Flask項(xiàng)目中獲取請(qǐng)求用戶IP地址 addr問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01