溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python迭代器協(xié)議和生成器知識總結(jié)

發(fā)布時間:2021-08-16 10:35:40 來源:億速云 閱讀:96 作者:chen 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Python迭代器協(xié)議和生成器知識總結(jié)”,在日常操作中,相信很多人在Python迭代器協(xié)議和生成器知識總結(jié)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Python迭代器協(xié)議和生成器知識總結(jié)”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

閱讀目錄

一 遞歸和迭代

二 什么是迭代器協(xié)議

三 python中強(qiáng)大的for循環(huán)機(jī)制

四 為何要有for循環(huán)

五 生成器初探

六 生成器函數(shù)

七 生成器表達(dá)式和列表解析

八 生成器總結(jié)

一 遞歸和迭代

二 什么是迭代器協(xié)議

1.迭代器協(xié)議是指:對象必須提供一個next方法,執(zhí)行該方法要么返回迭代中的下一項,要么就引起一個StopIteration異常,以終止迭代 (只能往后走不能往前退)

2.可迭代對象:實(shí)現(xiàn)了迭代器協(xié)議的對象(如何實(shí)現(xiàn):對象內(nèi)部定義一個__iter__()方法)

3.協(xié)議是一種約定,可迭代對象實(shí)現(xiàn)了迭代器協(xié)議,python的內(nèi)部工具(如for循環(huán),sum,min,max函數(shù)等)使用迭代器協(xié)議訪問對象。

三 python中強(qiáng)大的for循環(huán)機(jī)制

for循環(huán)的本質(zhì):循環(huán)所有對象,全都是使用迭代器協(xié)議。

正本清源:

很多人會想,for循環(huán)的本質(zhì)就是遵循迭代器協(xié)議去訪問對象,那么for循環(huán)的對象肯定都是迭代器了啊,沒錯,那既然這樣,for循環(huán)可以遍歷(字符串,列表,元組,字典,集合,文件對象),那這些類型的數(shù)據(jù)肯定都是可迭代對象?。康?,我他媽的為什么定義一個列表l=[1,2,3,4]沒有l(wèi).next()方法,打臉么。

(字符串,列表,元組,字典,集合,文件對象)這些都不是可迭代對象,只不過在for循環(huán)式,調(diào)用了他們內(nèi)部的__iter__方法,把他們變成了可迭代對象

然后for循環(huán)調(diào)用可迭代對象的__next__方法去取值,而且for循環(huán)會捕捉StopIteration異常,以終止迭代

 1 l=['a','b','c']

 2 #一:下標(biāo)訪問方式

 3 print(l[0])

 4 print(l[1])

 5 print(l[2])

 6 # print(l[3])#超出邊界報錯:IndexError

 7 

 8 #二:遵循迭代器協(xié)議訪問方式

 9 diedai_l=l.__iter__()

10 print(diedai_l.__next__())

11 print(diedai_l.__next__())

12 print(diedai_l.__next__())

13 # print(diedai_l.__next__())#超出邊界報錯:StopIteration

14 

15 #三:for循環(huán)訪問方式

16 #for循環(huán)l本質(zhì)就是遵循迭代器協(xié)議的訪問方式,先調(diào)用diedai_l=l.__iter__()方法,或者直接diedai_l=iter(l),然后依次執(zhí)行diedai_l.next(),直到for循環(huán)捕捉到StopIteration終止循環(huán)

  #for循環(huán)所有對象的本質(zhì)都是一樣的原理

17 

18 for i in l:#diedai_l=l.__iter__()

19     print(i) #i=diedai_l.next()

20 

21 #四:用while去模擬for循環(huán)做的事情

22 diedai_l=l.__iter__()

23 while True:

24     try:

25         print(diedai_l.__next__())

26     except StopIteration:

27         print('迭代完畢了,循環(huán)終止了')

28         break

四 為何要有for循環(huán)

基于上面講的列表的三種訪問方式,聰明的你立馬看除了端倪,于是你不知死活大聲喊道,你這不逗我玩呢么,有了下標(biāo)的訪問方式,我可以這樣遍歷一個列表啊

l=[1,2,3]

index=0

while index < len(l):

    print(l[index])

    index+=1

#要毛線for循環(huán),要毛線for循環(huán),要毛線for循環(huán)

沒錯,序列類型字符串,列表,元組都有下標(biāo),你用上述的方式訪問,perfect!但是你可曾想過非序列類型像字典,集合,文件對象的感受,所以嘛,年輕人,for循環(huán)就是基于迭代器協(xié)議提供了一個統(tǒng)一的可以遍歷所有對象的方法,即在遍歷之前,先調(diào)用對象的__iter__方法將其轉(zhuǎn)換成一個迭代器,然后使用迭代器協(xié)議去實(shí)現(xiàn)循環(huán)訪問,這樣所有的對象就都可以通過for循環(huán)來遍歷了,而且你看到的效果也確實(shí)如此,這就是無所不能的for循環(huán),覺悟吧,年輕人

五 生成器初探

什么是生成器?

可以理解為一種數(shù)據(jù)類型,這種數(shù)據(jù)類型自動實(shí)現(xiàn)了迭代器協(xié)議(其他的數(shù)據(jù)類型需要調(diào)用自己內(nèi)置的__iter__方法),所以生成器就是可迭代對象

生成器分類及在python中的表現(xiàn)形式:(Python有兩種不同的方式提供生成器)

1.生成器函數(shù):常規(guī)函數(shù)定義,但是,使用yield語句而不是return語句返回結(jié)果。yield語句一次返回一個結(jié)果,在每個結(jié)果中間,掛起函數(shù)的狀態(tài),以便下次重它離開的地方繼續(xù)執(zhí)行

2.生成器表達(dá)式:類似于列表推導(dǎo),但是,生成器返回按需產(chǎn)生結(jié)果的一個對象,而不是一次構(gòu)建一個結(jié)果列表

為何使用生成器之生成器的優(yōu)點(diǎn)

Python使用生成器對延遲操作提供了支持。所謂延遲操作,是指在需要的時候才產(chǎn)生結(jié)果,而不是立即產(chǎn)生結(jié)果。這也是生成器的主要好處。

生成器小結(jié):

1.是可迭代對象

2.實(shí)現(xiàn)了延遲計算,省內(nèi)存啊

3.生成器本質(zhì)和其他的數(shù)據(jù)類型一樣,都是實(shí)現(xiàn)了迭代器協(xié)議,只不過生成器附加了一個延遲計算省內(nèi)存的好處,其余的可迭代對象可沒有這點(diǎn)好處,記住嘍?。?!

六 生成器函數(shù)

七 生成器表達(dá)式和列表解析

總結(jié):

1.把列表解析的[]換成()得到的就是生成器表達(dá)式

2.列表解析與生成器表達(dá)式都是一種便利的編程方式,只不過生成器表達(dá)式更節(jié)省內(nèi)存

3.Python不但使用迭代器協(xié)議,讓for循環(huán)變得更加通用。大部分內(nèi)置函數(shù),也是使用迭代器協(xié)議訪問對象的。例如, sum函數(shù)是Python的內(nèi)置函數(shù),該函數(shù)使用迭代器協(xié)議訪問對象,而生成器實(shí)現(xiàn)了迭代器協(xié)議,所以,我們可以直接這樣計算一系列值的和:

1 sum(x ** 2 for x in xrange(4))

而不用多此一舉的先構(gòu)造一個列表:

1 sum([x ** 2 for x in xrange(4)]) 

八 生成器總結(jié)

綜上已經(jīng)對生成器有了一定的認(rèn)識,下面我們以生成器函數(shù)為例進(jìn)行總結(jié)

語法上和函數(shù)類似:生成器函數(shù)和常規(guī)函數(shù)幾乎是一樣的。它們都是使用def語句進(jìn)行定義,差別在于,生成器使用yield語句返回一個值,而常規(guī)函數(shù)使用return語句返回一個值

自動實(shí)現(xiàn)迭代器協(xié)議:對于生成器,Python會自動實(shí)現(xiàn)迭代器協(xié)議,以便應(yīng)用到迭代背景中(如for循環(huán),sum函數(shù))。由于生成器自動實(shí)現(xiàn)了迭代器協(xié)議,所以,我們可以調(diào)用它的next方法,并且,在沒有值可以返回的時候,生成器自動產(chǎn)生StopIteration異常

狀態(tài)掛起:生成器使用yield語句返回一個值。yield語句掛起該生成器函數(shù)的狀態(tài),保留足夠的信息,以便之后從它離開的地方繼續(xù)執(zhí)行

優(yōu)點(diǎn)一:生成器的好處是延遲計算,一次返回一個結(jié)果。也就是說,它不會一次生成所有的結(jié)果,這對于大數(shù)據(jù)量處理,將會非常有用。

1 #列表解析

2 sum([i for i in range(100000000)])#內(nèi)存占用大,機(jī)器容易卡死

4 #生成器表達(dá)式

5 sum(i for i in range(100000000))#幾乎不占內(nèi)存

優(yōu)點(diǎn)二:生成器還能有效提高代碼可讀性

 1 #求一段文字中,每個單詞出現(xiàn)的位置

 2 def index_words(text):

 3     result = []

 4     if text:

 5         result.append(0)

 6     for index, letter in enumerate(text, 1):

 7         if letter == ' ':

 8             result.append(index)

 9     return result

10 

11 print(index_words('hello alex da sb'))

#求一段文字中每個單詞出現(xiàn)的位置

def index_words(text):

    if text:

        yield 0

    for index, letter in enumerate(text, 1):

        if letter == ' ':

            yield index

g=index_words('hello alex da sb')

print(g)

print(g.__next__())

print(g.__next__())

print(g.__next__())

print(g.__next__())

print(g.__next__())#報錯

這里,至少有兩個充分的理由說明 ,使用生成器比不使用生成器代碼更加清晰:

使用生成器以后,代碼行數(shù)更少。大家要記住,如果想把代碼寫的Pythonic,在保證代碼可讀性的前提下,代碼行數(shù)越少越好

不使用生成器的時候,對于每次結(jié)果,我們首先看到的是result.append(index),其次,才是index。也就是說,我們每次看到的是一個列表的append操作,只是append的是我們想要的結(jié)果。使用生成器的時候,直接yield index,少了列表append操作的干擾,我們一眼就能夠看出,代碼是要返回index。

這個例子充分說明了,合理使用生成器,能夠有效提高代碼可讀性。只要大家完全接受了生成器的概念,理解了yield語句和return語句一樣,也是返回一個值。那么,就能夠理解為什么使用生成器比不使用生成器要好,能夠理解使用生成器真的可以讓代碼變得清晰易懂。

注意事項:生成器只能遍歷一次(母雞一生只能下一定數(shù)量的蛋,下完了就死掉了)

 1 人口信息.txt文件內(nèi)容

 2 {'name':'北京','population':10}

 3 {'name':'南京','population':100000}

 4 {'name':'山東','population':10000}

 5 {'name':'山西','population':19999}

 6 

 7 def get_provice_population(filename):

 8     with open(filename) as f:

 9         for line in f:

10             p=eval(line)

11             yield p['population']

12 gen=get_provice_population('人口信息.txt')

13 

14 all_population=sum(gen)

15 for p in gen:

16     print(p/all_population)

17 執(zhí)行上面這段代碼,將不會有任何輸出,這是因為,生成器只能遍歷一次。在我們執(zhí)行sum語句的時候,就遍歷了我們的生成器,當(dāng)我們再次遍歷我們的生成器的時候,將不會有任何記錄。所以,上面的代碼不會有任何輸出。

19 因此,生成器的唯一注意事項就是:生成器只能遍歷一次。

到此,關(guān)于“Python迭代器協(xié)議和生成器知識總結(jié)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI