在學習生成器之前,必須先了解一下迭代器。因為生成器就是一種特殊的迭代器,而且生成器用起來更加優雅。
迭代器的詳解可以參考我的另一篇博文:
先說一種比較簡單的生成器,通過例子慢慢來體會什麼是生成器。
#列表生成式
l = [x for x in range(5)]
(l)#
簡單的生成器
g = (x for x in range(5)) #
g就是乙個生成器,也是乙個迭代器,迭代器也是可迭代物件,所以這個g也可以說是可迭代物件
(next(g))
(next(g))
(next(g))
(next(g))
(next(g))
輸出:[0, 1, 2, 3, 4]01
234
把列表生成器的改為()就變成乙個簡單的生成器。由上面的例子,我們大概可以知道,生成器就是乙個迭代器,把資料乙個乙個拿出來,可以減少記憶體的負擔。
那麼,yield又是乙個什麼東西呢?為什麼說他優雅呢?
當我們寫的**輸出的結果,想乙個乙個出來。有兩種常用的方法:
方法1.我們可以建立乙個迭代器類,然後把**寫進類裡,用類來建立乙個可迭代物件,然後用next()函式乙個乙個把結果迭代出來。
方法2.我們可以用**函式的合適位置加上yield,這時候這個函式就變成乙個生成器了,不需要再建立乙個迭代器類,不需要再寫__iter__,__next__方法了。這樣一來不是很方便,很優雅嗎?哈哈哈哈~
口說無憑,下面我們2個方法都做一下,讓你們體會一下:
我們做乙個斐波那契的數列生成器。斐波那契數列的第乙個數是0,第二個數是1,第三個數是第
一、二個數相加,第四個數是第
二、三個數相加......
方法1:
classfeiboiterator():
def__init__
(self):
self.a =0
self.b = 1
def__iter__
(self):
return
self
def__next__
(self):
num =self.a
self.a,self.b = self.b,self.a+self.b
return
numiterator =feiboiterator()
(next(iterator))
(next(iterator))
(next(iterator))
(next(iterator))
(next(iterator))
(next(iterator))
(next(iterator))
(next(iterator))
輸出:012
35813
是不是很麻煩?又要初始化,又要寫__iter__和__next__魔方方法。
方法2:
deffeibo():
a =0
b = 1
while
true:
yield
a #假如yield後面緊接著乙個資料,就會把資料返回,作為next()函式或者for ...in...迭代出的下乙個值a,b = b,a+b
generator =feibo()
(next(generator))
(next(generator))
(next(generator))
(next(generator))
(next(generator))
(next(generator))
(next(generator))
(next(generator))
輸出:011
2358
13
看!只有6行**,是不是很elegant?關於這個程式是怎麼執行的?yield是怎麼運作的?我們等下就講,現在需要注意幾點:
1.上面**的紅色字那裡!假如yield後面緊接著乙個資料,就會把資料返回,作為next()函式或者for ...in...迭代出的下乙個值。
2.假如函式中有yield,就不再是函式。而是乙個能返回生成器的函式!注意!是返回,這個函式並不是乙個生成器。(修正:這句話發現有錯誤,這個函式也是乙個生成器)
3.拿到函式的生成器後,可以和迭代器一樣,用next()函式獲得下乙個值。
好了,該來理解一下yield是怎麼運作的了!
1.第一次喚醒生成器時,是從函式的起始位置開始,直到遇到yield,就會暫停函式,掛起函式。
2.第二次喚醒生成器時,是從yield斷點處開始,直到又遇到yield。
3.當生成器已經沒有yield,再使用next,則拋stopiteration異常。
然後,我們來理一下上面用yield寫的**。
第一次用next()喚醒生成器時,從函式的開頭開始執行,遇到yield a,返回a,然後暫停函式,並記住函式是執行到這個位置的。
第二次喚醒生成器,從yield a斷點處開始,然後a,b開始賦值,while true迴圈又遇見yield a,返回a,然後暫停函式,並記住函式是執行到這個位置的。
下面喚醒多少次都是這個道理,但是由於這個函式是死迴圈,所以不會沒有yield,也就不會丟擲stopiteration異常。
其實yield還能接受值,用send方法進行傳入。**體會一下:
defgg():
i = 1
while
true:
recv = yield
i
print("
接收到乙個值:
",recv)
i += 1generator =gg()
(next(generator))
print(generator.send("
456"
))print(generator.send("
789"
))輸出:
1接收到乙個值: 456
2接收到乙個值: 789
3
實現過程和上面的例子一樣。
要懂得的是,yield = a,會返回a。
b = yield,會把yield接收的值賦值給b。
Python中的生成器與yield
在python中使用了yield關鍵字的函式稱之為生成器。當我們呼叫該函式時並不會執行函式 而是返回乙個生成器物件。在呼叫生成器執行的過程中,每次遇到yield函式就會暫停並儲存當前的資訊,返回yield值,並在下次執行next 時,從此處開始繼續執行。from collections.abc im...
python中的yield用法,生成器關鍵字
接下來是正題 首先,如果你還沒有對yield有個初步分認識,那麼你先把yield看做 return 這個是直觀的,它首先是個return,普通的return是什麼意思,就是在程式中返回某個值,返回之後程式就不再往下執行了。看做return之後再把它看做乙個是生成器 generator 的一部分 帶y...
python生成器中yield和send分析
在python中生成器是指用 實現迭代器的的功能本質還是迭代器,只不過是 實現迭代器功能。在python中生成器是由函式實現的,通常我們在函式中加入yeild就可以實現生成器。定義乙個函式 def func print 111 yield 3 print 222 g func 執行上面 你會發現函式...