python的生成器

2021-10-23 04:28:52 字數 3143 閱讀 1830

生成器算是python中比較實用的乙個工具,但由於其他主流程式語言中沒有「生成器」這個概念,所以生成器經常容易被忽視。

那麼使用生成器有什麼好處呢?我認為好處有兩點:其一是減少記憶體的使用,其二是簡化**,同時可以增強**的可讀性

舉個栗子,比如要生成乙個斐波那契數列,如果不用生成器,而是用列表實現的話,**大致如下:

def

fib(n)

: prev, cur =0,

1 res =

while n >0:

n -=

1 prev, cur = cur, prev + cur

return res

print

(fib(10)

)#out:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

如上述**所示,如果使用列表這個資料結構,那麼需要在記憶體中儲存10個int型別的資料,你可能說這也就40個位元組,不打緊;但是如果這個型參n的傳入值為1000000000(十億),那就需要占用大概4gb的記憶體,電腦是不太容易吃得消的。

因此,對於資料量特別龐大的資料來說,用列表顯然非常耗費記憶體。這裡生成器就有用武之地了,我不需要一次性得到這麼多的資料,只是在用到的時候拿出來就好了。

如果改造成利用生成器實現斐波那契數列,**可以改寫為:

def

fib(n)

: prev, cur =0,

1while n >0:

n -=

1yield cur

prev, cur = cur, prev + cur

g = fib(10)

print

([i for i in g)])

#out:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

上面的**是利用生成器函式得到乙個生成器(有兩種構建生成器的方法,下面會有介紹)。從上面的**可以看出,生成器函式中有乙個關鍵字yield,這是表明這個函式是生成器函式的標誌,yield可以返回乙個值(與return類似);除此以外,每當執行到yield,相當於對這個函式狀態進行掛起,即暫時不再執行下去(並不是完全結束),需要有乙個事件來喚醒這個函式。

而喚醒這個函式的事件就是迭代器協議中的next(),我們知道,生成器是滿足迭代器協議的,即可以呼叫內建的next()函式來獲取下乙個元素的值,在python中,對於乙個迭代器做for迴圈,相當於不斷呼叫其next()函式,直到迭代器的下一項為空,此時會丟擲乙個stopiteration的異常來終止迭代。

因此,for迴圈每執行一次,相當於對滿足迭代器的物件g做一次next(),此時會喚醒經過yield後掛起的函式,使得生成器函式繼續向下執行。這樣就看出了生成器可以大大節省記憶體空間,因為生成器是按照需要產生資料的乙個物件,每一次呼叫next()只返回當前需要用到的數值即可,而不用儲存整個數列的資訊;同時上面生成器的**顯然要更加簡潔。

下面一段**可能對理解next()與掛起有著更好的幫助:

def

array

(n):

for i in

range(10

):print

("before return"

, i)

yield i

print

("after return"

, i)

g = array(10)

print

(g)#g一開始表示生成器物件的位址

#out:

print

(next

(g))

"""before return 0

0"""

print

(next

(g))

"""after return 0

before return 1

1"""

print

(next

(g))

"""after return 1

before return 2

2"""

通過上面的**可以看出,第一次呼叫next()函式時,yield一行將0返回以後,暫時中止了向下執行,也就是說yield使生成器函式變為掛起狀態。當第二次執行next()函式,就喚醒了生成器函式,從上一次中止的地方繼續向下執行。

建立生成器的兩種方式

第一種是利用生成器函式(關鍵字yield),上面已經介紹過,這裡不贅述啦。

第二種是生成器表示式,例如求乙個2的n次方的數列,**可以寫為:

g1 =

(pow(2

, x)

for x in

range(10

))print

([i for i in g1]

)#out:[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

和產生列表的方式比較類似,只不過將方括號改為圓括號即可。

注意事項

python中的生成器只能遍歷一遍,看下面一段**:

g1 =

(pow(2

, x)

for x in

range(10

))print

([i for i in g1]

)#out:[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

print

([i for i in g1]

)#out:

可以發現,第二次遍歷生成器g1的時候,就已經失去了效果。因為在第一次遍歷後,已經指向了結束的位置,所以第二次遍歷將不會再有結果。

總結python生成器的好處大致是節省記憶體,簡化**;

生成器的構造有兩種方法:生成器函式(含yield關鍵字)和生成器表示式(圓括號);

生成器滿足迭代器協議,即可以通過next()函式訪問下乙個值。如果使用yield關鍵字,在返回乙個值的同時掛起該生成器函式,直到下一次next()來喚醒該函式,之後在剛才中斷的地方繼續向下執行。

python 生成器作用 Python生成器

生成器介紹 在函式內部包含yield關鍵字,那麼該函式執行的結果是生成器,生成器就是迭代器。生成器的功能 把函式結果做成迭代器 以一種優雅的方式封裝好iter,next 提供了一種自己定義迭代器的方式。使用生成器建立乙個迭代器 def a print a yield 11 使用yield,執行後返回...

python生成器好處 Python生成器筆記

python中三大器有迭代器,生成器,裝飾器,本文主要講述生成器。主要從生成器的概念,本質,以及yield關鍵字的使用執行過程。本質 生成器是一類特殊的迭代器,使用了yield關鍵字的函式不再是函式,而是生成器。使用了yield的函式就是生成器 1.yield關鍵字有兩點作用 1.1 yield語句...

python生成器函式 Python 生成器函式

一 生成器 生成器指的是生成器物件,可由生成器表示式得到,也可使用 yield 關鍵字得到乙個生成器函式,呼叫這個函式得到乙個生成器物件 生成器物件,是乙個可迭代物件,是乙個迭代器 生成器物件,是延遲計算 惰性求值的 1.1 生成器函式 函式體重包含 yield 語句的函式,就是生成器函式,呼叫後返...