Python迭代器協(xié)議及for循環(huán)工作機(jī)制詳解
一、遞歸與迭代
二、什么是迭代器協(xié)議
1、迭代器協(xié)議是指:對(duì)象必須提供一個(gè)next方法,執(zhí)行該方法要么返回迭代中的下一項(xiàng),要么就引起一個(gè)stopiteration異常,已終止迭代(只能往后走不能往前退)
2、可迭代對(duì)象:實(shí)現(xiàn)了迭代器協(xié)議的對(duì)象(如何實(shí)現(xiàn):對(duì)象內(nèi)部定義一個(gè)__iter__()方法)
3、協(xié)議是一種約定,可迭代對(duì)象實(shí)現(xiàn)了迭代器協(xié)議,python的內(nèi)部工具(如for循環(huán),sum,min,max函數(shù)等)使用迭代器協(xié)議訪問對(duì)象。
三、python中強(qiáng)大的for循環(huán)機(jī)制
for循環(huán)的本質(zhì):循環(huán)所有對(duì)象,全部是使用迭代器協(xié)議
解釋:
有時(shí)會(huì)想,for循環(huán)的本質(zhì)就是遵循迭代器協(xié)議訪問對(duì)象,那么for循環(huán)的對(duì)象肯定都是迭代器了啊,沒錯(cuò),那既然這樣,for循環(huán)可以遍歷(字符串,,列表,字典,集合,文件對(duì)象),那這些類型的數(shù)據(jù)肯定都是可迭代對(duì)象?。康?,為什么定義一個(gè)列表l=[1,2,3,4]沒有next()方法。
(字符串,列表,元組,字典,集合,文件對(duì)象)這些都不是可迭代對(duì)象,只不過在for循環(huán)中,調(diào)用了他們內(nèi)部的__iter__方法,把他們變成了可迭代對(duì)象
然后for循環(huán)調(diào)用可迭代對(duì)象的__next__方法去取值,而且for循環(huán)會(huì)捕捉stoplteration異常,已終止迭代
l=[1,2,3,4,5] #下標(biāo)訪問方式 print(l[0]) print(l[7]) #超出訪問會(huì)報(bào)IndexError: list index out of range #遵循迭代器協(xié)議的方式 diedai=l.__iter__() print(diedai.__next__()) print(diedai.__next__()) print(diedai.__next__()) print(diedai.__next__()) print(diedai.__next__()) print(diedai.__next__()) #超出邊界會(huì)報(bào)StopIteration #for循環(huán)訪問方式: #for循環(huán)本質(zhì)就是遵循迭代器協(xié)議的訪問方式,先調(diào)用diedai.__iter__()方法,或者直接diedai=iter(l),然后依次執(zhí)行diedai.next(),直到for循環(huán)捕捉到StopIteration終止循環(huán) #for循環(huán)所有對(duì)象的本質(zhì)都是一樣的道理 for i in l: #diedai=l.__iter__() print(l[i]) #i=diedai.next() #使用while模擬for循環(huán)做的事情 diedai_l=l.__iter__() while True: try: print(diedai_l.__next__()) except StopIteration: print("迭代完畢,終止循環(huán)") break
四、生成器初探
什么是生成器?
可以理解為一種數(shù)據(jù)類型,這種數(shù)據(jù)類型自動(dòng)實(shí)現(xiàn)了迭代器協(xié)議(其他的數(shù)據(jù)類型需要調(diào)用自己內(nèi)置的__iter__方法),所以生成器就是可迭代對(duì)象
生成器分類及在python中的表現(xiàn)形式:(python有兩種不同的方法提供生成器)
1、生成器函數(shù):常規(guī)函數(shù)定義,但是,使用yield語(yǔ)句而不是return語(yǔ)句返回結(jié)果。yield語(yǔ)句一次返回一個(gè)結(jié)果,在沒個(gè)結(jié)果中間,掛起函數(shù)的狀態(tài),以便下次用它離開的地方繼續(xù)執(zhí)行
2、生成器表達(dá)式:類似于列表推導(dǎo),但是,生成器返回按需產(chǎn)生結(jié)果的一個(gè)對(duì)象,而不是一次構(gòu)建一個(gè)結(jié)果列表
為何使用生成器以及生產(chǎn)器的優(yōu)點(diǎn):
python使用生成器對(duì)延遲操作提供了支持,所謂延遲操作,是指在需要的時(shí)候才產(chǎn)生結(jié)果,而不是立即產(chǎn)生結(jié)果,這也是生產(chǎn)器的重要好處
import time # def producer(): # ret=[] # for i in range(100): # time.sleep(0.1) # ret.append('包子%s' %i) # return ret # # def consumer(res): # for index,baozi in enumerate(res): # time.sleep(0.1) # print('第%s個(gè)人,吃了%s' %(index,baozi)) # # res=producer() # consumer(res) #yield 3相當(dāng)于return 控制的是函數(shù)的返回值 #x=yield的另外一個(gè)特性,接受send傳過來的值,賦值給x # def test(): # print('開始啦') # firt=yield #return 1 first=None # print('第一次',firt) # yield 2 # print('第二次') # # t=test() # res=t.__next__() #next(t) # print(res) # # t.__next__() # # res=t.send(None) # res=t.send('函數(shù)停留在first那個(gè)位置,我就是給first賦值的') # print(res) # def producer(): # ret=[] # for i in range(100): # time.sleep(0.1) # ret.append('包子%s' %i) # return ret def consumer(name): print('我是[%s],我準(zhǔn)備開始吃包子了' %name) while True: baozi=yield time.sleep(1) print('%s 很開心的把【%s】吃掉了' %(name,baozi)) def producer(): c1=consumer('wupeiqi') c2=consumer('yuanhao_SB') c1.__next__() c2.__next__() for i in range(10): time.sleep(1) c1.send('包子 %s' %i) c2.send('包子 %s' %i) producer()
生產(chǎn)器小結(jié)
1、生成器是可迭代對(duì)象
2、實(shí)現(xiàn)了延遲計(jì)算、省內(nèi)存
3、生成器本質(zhì)和其他的數(shù)據(jù)類型一樣,都是實(shí)現(xiàn)了迭代器協(xié)議,只不過生成器附加了一個(gè)延遲計(jì)算省內(nèi)存的好處,其余的可迭代對(duì)象可沒有這點(diǎn)好處
五、生成器表達(dá)式和列表解析
#1、三元表達(dá)式 name="alex" name="yangyl" res="1" if name=="yangyl" else "2" print(res) egg_list=["雞蛋%s" %i for i in range(10) ] #列表解析 print(egg_list) #使用生產(chǎn)器獲取 egg_two=("雞蛋%s" %i for i in range(10)) #生產(chǎn)器表達(dá)式 print(egg_two) print(egg_two.__next__()) print(next(egg_two)) #next()本質(zhì)就是調(diào)用__next__
總結(jié):
1、把列表解析中的[]換成() 得到的就是生成器表達(dá)式
2、列表解析與生成器表達(dá)式都是一種便利的編程方式,只不過生成器表達(dá)式更節(jié)省內(nèi)存
3、python不但使用迭代器協(xié)議,讓for循環(huán)變得更加通用。大部分內(nèi)置函數(shù),也是使用迭代器協(xié)議訪問對(duì)象的。列如:sum函數(shù)是python的內(nèi)置函數(shù),該函數(shù)使用迭代器協(xié)議訪問對(duì)象,而生成器實(shí)現(xiàn)了迭代器協(xié)議,所以我們可以直接這樣計(jì)算一系列值的和:
s1=sum(x ** 2 for x in range(4))
print(s1)
而不用多此一舉先構(gòu)造一個(gè)列表
s2=sum([x ** 2 for x in range(4)])
print(s2)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python讀取配置文件-ConfigParser的二次封裝方法
這篇文章主要介紹了Python讀取配置文件-ConfigParser的二次封裝方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Tensorflow 2.4 搭建單層和多層 Bi-LSTM 模型
這篇文章主要為大家介紹了Tensorflow 2.4 搭建單層 Bi-LSTM 模型和多層 Bi-LSTM 模型的實(shí)現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Django壓縮靜態(tài)文件的實(shí)現(xiàn)方法詳析
最近在學(xué)習(xí)Django配置靜態(tài)文件,下面這篇文章主要給大家介紹了關(guān)于Django壓縮靜態(tài)文件的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08