python中的yield生成器詳解

2022-07-04 01:06:07 字數 3544 閱讀 3299

在學習生成器之前,必須先了解一下迭代器。因為生成器就是一種特殊的迭代器,而且生成器用起來更加優雅。

迭代器的詳解可以參考我的另一篇博文:

先說一種比較簡單的生成器,通過例子慢慢來體會什麼是生成器。

#

列表生成式

l = [x for x in range(5)]

print

(l)#

簡單的生成器

g = (x for x in range(5)) #

g就是乙個生成器,也是乙個迭代器,迭代器也是可迭代物件,所以這個g也可以說是可迭代物件

print

(next(g))

print

(next(g))

print

(next(g))

print

(next(g))

print

(next(g))

輸出:[0, 1, 2, 3, 4]01

234

把列表生成器的改為()就變成乙個簡單的生成器。由上面的例子,我們大概可以知道,生成器就是乙個迭代器,把資料乙個乙個拿出來,可以減少記憶體的負擔。

那麼,yield又是乙個什麼東西呢?為什麼說他優雅呢?

當我們寫的**輸出的結果,想乙個乙個出來。有兩種常用的方法:

方法1.我們可以建立乙個迭代器類,然後把**寫進類裡,用類來建立乙個可迭代物件,然後用next()函式乙個乙個把結果迭代出來。

方法2.我們可以用**函式的合適位置加上yield,這時候這個函式就變成乙個生成器了,不需要再建立乙個迭代器類,不需要再寫__iter__,__next__方法了。這樣一來不是很方便,很優雅嗎?哈哈哈哈~

口說無憑,下面我們2個方法都做一下,讓你們體會一下:

我們做乙個斐波那契的數列生成器。斐波那契數列的第乙個數是0,第二個數是1,第三個數是第

一、二個數相加,第四個數是第

二、三個數相加......

方法1:

class

feiboiterator():

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()

print

(next(iterator))

print

(next(iterator))

print

(next(iterator))

print

(next(iterator))

print

(next(iterator))

print

(next(iterator))

print

(next(iterator))

print

(next(iterator))

輸出:012

35813

是不是很麻煩?又要初始化,又要寫__iter__和__next__魔方方法。

方法2:

def

feibo():

a =0

b = 1

while

true:

yield

a #假如yield後面緊接著乙個資料,就會把資料返回,作為next()函式或者for ...in...迭代出的下乙個值a,b = b,a+b

generator =feibo()

print

(next(generator))

print

(next(generator))

print

(next(generator))

print

(next(generator))

print

(next(generator))

print

(next(generator))

print

(next(generator))

print

(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方法進行傳入。**體會一下:

def

gg():

i = 1

while

true:

recv = yield

i

print("

接收到乙個值:

",recv)

i += 1generator =gg()

print

(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 執行上面 你會發現函式...