Python編程中實(shí)現(xiàn)迭代器的一些技巧小結(jié)
yield實(shí)現(xiàn)迭代器
如引言中的描述,實(shí)現(xiàn)一個可迭代的功能要是每次都手動實(shí)現(xiàn)iter,next稍稍有點(diǎn)麻煩,所需的代碼也是比較客觀。在python中也能通過借助yield的方式來實(shí)現(xiàn)一個迭代器。yield有一個關(guān)鍵的作能,它能夠中斷當(dāng)前的執(zhí)行邏輯,保持住現(xiàn)場(各種值的狀態(tài),執(zhí)行的位置等等),返回相應(yīng)的值,下一次執(zhí)行的時候能夠無縫的接著上次的地方繼續(xù)執(zhí)行,如此循環(huán)反復(fù)知道滿足事先設(shè)置的退出條件或者發(fā)生錯誤強(qiáng)制被中斷。
其具體功能是可以當(dāng)return使用,從函數(shù)里返回一個值,不同之處是用yield返回之后,可以讓函數(shù)從上回yield返回的地點(diǎn)繼續(xù)執(zhí)行。也就是說,yield返回函數(shù),交給調(diào)用者一個返回值,然后再“瞬移”回去,讓函數(shù)繼續(xù)運(yùn)行, 直到嚇一跳yield語句再返回一個新的值。使用yield返回后,調(diào)用者實(shí)際得到的是一個迭代器對象,迭代器的值就是返回值,而調(diào)用該迭代器的next()方法會導(dǎo)致該函數(shù)恢復(fù)yield語句的執(zhí)行環(huán)境繼續(xù)往下跑,直到遇到下一個yield為止,如果遇不到y(tǒng)ield,就會拋出異常表示迭代結(jié)束。
看一個例子:
>>> def test_yield(): ... yield 1 ... yield 2 ... yield (1,2) ... >>> a = test_yield() >>> a.next() 1 >>> a.next() 2 >>> a.next() (1, 2) >>> a.next() Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration
光聽描述就覺得和迭代器的工作方式很一致是吧,的確,yield能把它所在的函索變成一個迭代器,拿最經(jīng)典的菲波那切數(shù)列的例子聊簡述一下工作的方式:
def fab(max): n, a, b = 0, 0, 1 while n < max: print b, "is generated" yield b a, b = b, a + b n = n + 1 >>> for item in fab(5): ... print item ... 1 is generated 1 1 is generated 1 2 is generated 2 3 is generated 3 5 is generated 5
我們有回想一下for關(guān)鍵字的語法糖,在這里遍歷5以內(nèi)的菲波那切數(shù)列值的時候,很顯然fab(5)生成了一個可迭代的對象,遍歷開始的時候它的iter方法被調(diào)用返回一個實(shí)際工作的迭代器對象,然后每一次調(diào)用它的next方法返回一個菲波那切數(shù)列值然后打印出來。
我們可以將調(diào)用生成器函數(shù)返回的對象的屬性打印出來,看一下到底發(fā)生了什么:
>>> temp_gen = fab(5) >>> dir(temp_gen) ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
正如上面的描述,單純調(diào)用fab并不會讓函數(shù)立刻開始返回任何值,并且從打印出的fab(5)的屬性列表能夠看到,生成器函數(shù)返回的對象包含有__iter__,next的實(shí)現(xiàn)。與我們手動實(shí)現(xiàn)相比,使用yield很方便的就能夠?qū)崿F(xiàn)我們想要的功能,代碼量縮減不少。
Generator Expression
python中另一種能更優(yōu)雅生成迭代器對象的方式就是使用生成器表達(dá)式Generator expression,它和列表解析表達(dá)式有著非常相似的寫法,僅僅是把中括號[]變成()而已,不過小小改變產(chǎn)生的實(shí)際效果確實(shí)大大的不一樣:
>>> temp_gen = (x for x in range(5)) >>> temp_gen <generator object <genexpr> at 0x7192d8> >>> for item in temp_gen: ... print item ... 0 1 2 3 4 >>> dir(temp_gen) ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
看過上面對yield的描述,這個例子以及對應(yīng)的輸出日志還是相當(dāng)直接明了的,無論是temp_gen的打印日志描述,for語句遍歷的輸出結(jié)果還是調(diào)用dir輸出的屬性列表,都赤裸裸的表明生成器表達(dá)式確實(shí)生成了能夠支持迭代的對象。另外表達(dá)式里面也能夠調(diào)用函數(shù),增加適量的過濾條件。
內(nèi)置庫itertools 和 iter
python內(nèi)置的庫itertools提供了大量的工具方法,這些方法能夠幫助我們創(chuàng)建能進(jìn)行高效遍歷和迭代的對象,里面包含不少有意思并且有用的方法,比如像chain, izip/izip_longest, combinations, ifilter等等。在python中還有一個內(nèi)置的iter函數(shù)非常有用,能夠返回一個迭代器對象,之后也就能夠進(jìn)行可以查看對應(yīng)的幫助文檔簡單看一下:
>>> iter('abc') <iterator object at 0x718590> >>> str_iterator = iter('abc') >>> next(str_iterator) 'a' >>> next(str_iterator) 'b' >>> lst_gen = iter([1,2,3,4]) >>> lst_gen <listiterator object at 0x728e30> >>> dir(lst_gen) ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__length_hint__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'next'] >>> help(iter) Help on built-in function iter in module builtins: iter(...) iter(iterable) -> iterator iter(callable, sentinel) -> iterator Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.
相關(guān)文章
用Q-learning算法實(shí)現(xiàn)自動走迷宮機(jī)器人的方法示例
這篇文章主要介紹了用Q-learning算法實(shí)現(xiàn)自動走迷宮機(jī)器人的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Python使用pytest-playwright的原因分析
pytest-playwright 是一個 Python 包,它允許您使用 Microsoft 的 Playwright 庫在 Python 項(xiàng)目中進(jìn)行端到端測試,這篇文章主要介紹了Python為什么使用pytest-playwright,需要的朋友可以參考下2023-03-03python初步實(shí)現(xiàn)word2vec操作
這篇文章主要介紹了python初步實(shí)現(xiàn)word2vec操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06