国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

深入講解Python中的迭代器和生成器

2020-01-04 17:58:23
字體:
供稿:網(wǎng)友

這篇文章主要介紹了Python中的迭代器和生成器,涉及到Python中很多重要的特性,需要的朋友可以參考下

在Python中,很多對(duì)象都是可以通過for語句來直接遍歷的,例如list、string、dict等等,這些對(duì)象都可以被稱為可迭代對(duì)象。至于說哪些對(duì)象是可以被迭代訪問的,就要了解一下迭代器相關(guān)的知識(shí)了。

迭代器

迭代器對(duì)象要求支持迭代器協(xié)議的對(duì)象,在Python中,支持迭代器協(xié)議就是實(shí)現(xiàn)對(duì)象的__iter__()和next()方法。其中__iter__()方法返回迭代器對(duì)象本身;next()方法返回容器的下一個(gè)元素,在結(jié)尾時(shí)引發(fā)StopIteration異常。

__iter__()和next()方法

這兩個(gè)方法是迭代器最基本的方法,一個(gè)用來獲得迭代器對(duì)象,一個(gè)用來獲取容器中的下一個(gè)元素。

對(duì)于可迭代對(duì)象,可以使用內(nèi)建函數(shù)iter()來獲取它的迭代器對(duì)象:

深入講解Python中的迭代器和生成器

例子中,通過iter()方法獲得了list的迭代器對(duì)象,然后就可以通過next()方法來訪問list中的元素了。當(dāng)容器中沒有可訪問的元素后,next()方法將會(huì)拋出一個(gè)StopIteration異常終止迭代器。

其實(shí),當(dāng)我們使用for語句的時(shí)候,for語句就會(huì)自動(dòng)的通過__iter__()方法來獲得迭代器對(duì)象,并且通過next()方法來獲取下一個(gè)元素。

自定義迭代器

了解了迭代器協(xié)議之后,就可以自定義迭代器了。

下面例子中實(shí)現(xiàn)了一個(gè)MyRange的類型,這個(gè)類型中實(shí)現(xiàn)了__iter__()方法,通過這個(gè)方法返回對(duì)象本身作為迭代器對(duì)象;同時(shí),實(shí)現(xiàn)了next()方法用來獲取容器中的下一個(gè)元素,當(dāng)沒有可訪問元素后,就拋出StopIteration異常。

 

 
  1. class MyRange(object): 
  2. def __init__(self, n): 
  3. self.idx = 0 
  4. self.n = n 
  5.  
  6. def __iter__(self): 
  7. return self 
  8.  
  9. def next(self): 
  10. if self.idx < self.n: 
  11. val = self.idx 
  12. self.idx += 1 
  13. return val 
  14. else
  15. raise StopIteration() 
  16.  
  17. class MyRange(object): 
  18. def __init__(self, n): 
  19. self.idx = 0 
  20. self.n = n 
  21.  
  22. def __iter__(self): 
  23. return self 
  24.  
  25. def next(self): 
  26. if self.idx < self.n: 
  27. val = self.idx 
  28. self.idx += 1 
  29. return val 
  30. else
  31. raise StopIteration() 

這個(gè)自定義類型跟內(nèi)建函數(shù)xrange很類似,看一下運(yùn)行結(jié)果:

 

 
  1. myRange = MyRange(3) 
  2. for i in myRange: 
  3. print i 

深入講解Python中的迭代器和生成器

迭代器和可迭代對(duì)象

在上面的例子中,myRange這個(gè)對(duì)象就是一個(gè)可迭代對(duì)象,同時(shí)它本身也是一個(gè)迭代器對(duì)象。

看下面的代碼,對(duì)于一個(gè)可迭代對(duì)象,如果它本身又是一個(gè)迭代器對(duì)象,就會(huì)有下面的 問題,就沒有辦法支持多次迭代。

深入講解Python中的迭代器和生成器

為了解決上面的問題,可以分別定義可迭代類型對(duì)象和迭代器類型對(duì)象;然后可迭代類型對(duì)象的__iter__()方法可以獲得一個(gè)迭代器類型的對(duì)象。看下面的實(shí)現(xiàn):

 

 
  1. class Zrange: 
  2. def __init__(self, n): 
  3. self.n = n 
  4.  
  5. def __iter__(self): 
  6. return ZrangeIterator(self.n) 
  7.  
  8. class ZrangeIterator: 
  9. def __init__(self, n): 
  10. self.i = 0 
  11. self.n = n 
  12.  
  13. def __iter__(self): 
  14. return self 
  15.  
  16. def next(self): 
  17. if self.i < self.n: 
  18. i = self.i 
  19. self.i += 1 
  20. return i 
  21. else
  22. raise StopIteration()  
  23.  
  24. zrange = Zrange(3) 
  25. print zrange is iter(zrange)  
  26.  
  27. print [i for i in zrange] 
  28. print [i for i in zrange] 

代碼的運(yùn)行結(jié)果為:

深入講解Python中的迭代器和生成器

其實(shí),通過下面代碼可以看出,list類型也是按照上面的方式,list本身是一個(gè)可迭代對(duì)象,通過iter()方法可以獲得list的迭代器對(duì)象:

深入講解Python中的迭代器和生成器

生成器

在Python中,使用生成器可以很方便的支持迭代器協(xié)議。生成器通過生成器函數(shù)產(chǎn)生,生成器函數(shù)可以通過常規(guī)的def語句來定義,但是不用return返回,而是用yield一次返回一個(gè)結(jié)果,在每個(gè)結(jié)果之間掛起和繼續(xù)它們的狀態(tài),來自動(dòng)實(shí)現(xiàn)迭代協(xié)議。

也就是說,yield是一個(gè)語法糖,內(nèi)部實(shí)現(xiàn)支持了迭代器協(xié)議,同時(shí)yield內(nèi)部是一個(gè)狀態(tài)機(jī),維護(hù)著掛起和繼續(xù)的狀態(tài)。

下面看看生成器的使用:

深入講解Python中的迭代器和生成器

在這個(gè)例子中,定義了一個(gè)生成器函數(shù),函數(shù)返回一個(gè)生成器對(duì)象,然后就可以通過for語句進(jìn)行迭代訪問了。

其實(shí),生成器函數(shù)返回生成器的迭代器。 “生成器的迭代器”這個(gè)術(shù)語通常被稱作”生成器”。要注意的是生成器就是一類特殊的迭代器。作為一個(gè)迭代器,生成器必須要定義一些方法,其中一個(gè)就是next()。如同迭代器一樣,我們可以使用next()函數(shù)來獲取下一個(gè)值。

生成器執(zhí)行流程

下面就仔細(xì)看看生成器是怎么工作的。

從上面的例子也可以看到,生成器函數(shù)跟普通的函數(shù)是有很大差別的。

結(jié)合上面的例子我們加入一些打印信息,進(jìn)一步看看生成器的執(zhí)行流程:

深入講解Python中的迭代器和生成器

通過結(jié)果可以看到:

當(dāng)調(diào)用生成器函數(shù)的時(shí)候,函數(shù)只是返回了一個(gè)生成器對(duì)象,并沒有 執(zhí)行。

當(dāng)next()方法第一次被調(diào)用的時(shí)候,生成器函數(shù)才開始執(zhí)行,執(zhí)行到y(tǒng)ield語句處停止

next()方法的返回值就是yield語句處的參數(shù)(yielded value)

當(dāng)繼續(xù)調(diào)用next()方法的時(shí)候,函數(shù)將接著上一次停止的yield語句處繼續(xù)執(zhí)行,并到下一個(gè)yield處停止;如果后面沒有yield就拋出StopIteration異常。

生成器表達(dá)式

在開始介紹生成器表達(dá)式之前,先看看我們比較熟悉的列表解析( List comprehensions),列表解析一般都是下面的形式。

 

 
  1. [expr for iter_var in iterable if cond_expr] 

迭代iterable里所有內(nèi)容,每一次迭代后,把iterable里滿足cond_expr條件的內(nèi)容放到iter_var中,再在表達(dá)式expr中應(yīng)該iter_var的內(nèi)容,最后用表達(dá)式的計(jì)算值生成一個(gè)列表。

例如,生成一個(gè)list來保護(hù)50以內(nèi)的所以奇數(shù):

 

 
  1. [i for i in range(50) if i%2] 

生成器表達(dá)式是在python2.4中引入的,當(dāng)序列過長, 而每次只需要獲取一個(gè)元素時(shí),應(yīng)當(dāng)考慮使用生成器表達(dá)式而不是列表解析。生成器表達(dá)式的語法和列表解析一樣,只不過生成器表達(dá)式是被()括起來的,而不是[],如下:

 

 
  1. (expr for iter_var in iterable if cond_expr) 

看一個(gè)例子:

深入講解Python中的迭代器和生成器

生成器表達(dá)式并不是創(chuàng)建一個(gè)列表, 而是返回一個(gè)生成器,這個(gè)生成器在每次計(jì)算出一個(gè)條目后,把這個(gè)條目”產(chǎn)生”(yield)出來。 生成器表達(dá)式使用了”惰性計(jì)算”(lazy evaluation),只有在檢索時(shí)才被賦值(evaluated),所以在列表比較長的情況下使用內(nèi)存上更有效。

繼續(xù)看一個(gè)例子:

深入講解Python中的迭代器和生成器

從這個(gè)例子中可以看到,生成器表達(dá)式產(chǎn)生的生成器,它自身是一個(gè)可迭代對(duì)象,同時(shí)也是迭代器本身。

遞歸生成器

生成器可以向函數(shù)一樣進(jìn)行遞歸使用的,下面看一個(gè)簡單的例子,對(duì)一個(gè)序列進(jìn)行全排列:

 

 
  1. def permutations(li): 
  2. if len(li) == 0: 
  3. yield li 
  4. else
  5. for i in range(len(li)): 
  6. li[0], li[i] = li[i], li[0] 
  7. for item in permutations(li[1:]): 
  8. yield [li[0]] + item 
  9.  
  10. for item in permutations(range(3)): 
  11. print item 
  12.  
  13. def permutations(li): 
  14. if len(li) == 0: 
  15. yield li 
  16. else
  17. for i in range(len(li)): 
  18. li[0], li[i] = li[i], li[0] 
  19. for item in permutations(li[1:]): 
  20. yield [li[0]] + item 
  21.  
  22. for item in permutations(range(3)): 
  23. print item 

生成器的send()和close()方法

生成器中還有兩個(gè)很重要的方法:send()和close()。

send(value):

從前面了解到,next()方法可以恢復(fù)生成器狀態(tài)并繼續(xù)執(zhí)行,其實(shí)send()是除next()外另一個(gè)恢復(fù)生成器的方法。

Python 2.5中,yield語句變成了yield表達(dá)式,也就是說yield可以有一個(gè)值,而這個(gè)值就是send()方法的參數(shù),所以send(None)和next()是等效的。同樣,next()和send()的返回值都是yield語句處的參數(shù)(yielded value)

關(guān)于send()方法需要注意的是:調(diào)用send傳入非None值前,生成器必須處于掛起狀態(tài),否則將拋出異常。也就是說,第一次調(diào)用時(shí),要使用next()語句或send(None),因?yàn)闆]有yield語句來接收這個(gè)值。

close():

這個(gè)方法用于關(guān)閉生成器,對(duì)關(guān)閉的生成器后再次調(diào)用next或send將拋出StopIteration異常。

下面看看這兩個(gè)方法的使用:

#FormatImgID_9#

總結(jié)

本文介紹了Python迭代器和生成器的相關(guān)內(nèi)容。

通過實(shí)現(xiàn)迭代器協(xié)議對(duì)應(yīng)的__iter__()和next()方法,可以自定義迭代器類型。對(duì)于可迭代對(duì)象,for語句可以通過iter()方法獲取迭代器,并且通過next()方法獲得容器的下一個(gè)元素。

像列表這種序列類型的對(duì)象,可迭代對(duì)象和迭代器對(duì)象是相互獨(dú)立存在的,在迭代的過程中各個(gè)迭代器相互獨(dú)立;但是,有的可迭代對(duì)象本身又是迭代器對(duì)象,那么迭代器就沒法獨(dú)立使用。

itertools模塊提供了一系列迭代器,能夠幫助用戶輕松地使用排列、組合、笛卡爾積或其他組合結(jié)構(gòu)。

生成器是一種特殊的迭代器,內(nèi)部支持了生成器協(xié)議,不需要明確定義__iter__()和next()方法。

生成器通過生成器函數(shù)產(chǎn)生,生成器函數(shù)可以通過常規(guī)的def語句來定義,但是不用return返回,而是用yield一次返回一個(gè)結(jié)果。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: SHOW| 华宁县| 台州市| 缙云县| 大方县| 同德县| 梁河县| 山东| 绥德县| 彭山县| 黎城县| 简阳市| 宁南县| 犍为县| 巩留县| 和龙市| 陵川县| 龙里县| 莱州市| 长治市| 印江| 大田县| 屯门区| 安乡县| 陵川县| 定远县| 靖远县| 右玉县| 龙岩市| 吉水县| 珲春市| 英超| 斗六市| 甘德县| 濮阳县| 镇安县| 射阳县| 隆安县| 望都县| 潞西市| 灯塔市|