1. 程式人生 > >Python進階系列連載(5)——生成器(上)

Python進階系列連載(5)——生成器(上)

生成器

還記得在迭代器裡我們說為什麼將列表轉為迭代器麼?

小明:因為列表太大的話佔用記憶體太大,做成迭代器可以節省空間,用的時候再拿出部分

是的,今天要講的生成器是不會把結果儲存在一個系列中,而是儲存生成器的狀態。

在每次進行迭代時返回一個值,直到遇到StopIteration異常結束。

見過這種東西吧:

你可以認為每一杯飲料就是一個生成的物件,我不會一次倒出所有的飲料

而是要喝的時候去倒出一杯(也就是需要的時候生成一個)

簡單方法建立生成器

我們看個例子:

我們發現,當要生成的list非常大時,丟擲異常,儲存報錯。

那怎樣生成這種巨大的list呢?

你親手試一下,發現瞬間程式就執行結束了

我們看到,b是一個generator,也就是生成器模式

你應該已經注意到,生成器的建立很簡單,將列表生成式的中括號改成小括號即可

注意:這裡說的不是列表,因為列表的中括號改成小括號是元組!

那我們怎麼生成一個內容呢?

和之前的迭代器相同,使用next()函式即可:

直到最後會丟擲異常,也就是到達了生成器的末端了

函式進化為生成器

還記得函式的定義麼?

我們在之前用遞迴定義了一個斐波那契數列

現在我們定義一個新的函式來生成斐波那契數列的第n項

為了實現後一項等於前兩項之和使用了a,b = b,a+b

為什麼這樣寫,留給大家思考~

提示:可以輸入n=3,自己感受一下呼叫函式過程中a和b的變化

值得注意的是,這個函式,當n=0時返回的是1,而不是正確的0

所以我們對其進行修改:

在迴圈之前,加了一個判斷

小明:老溼!你這個說的還是函式啊,和生成器有啥關係?說好的函式進化成生成器呢?

好的,我們看看函式怎麼進化為生成器!

我們把函式中的return換成yield

函式就進化成了生成器,當我們呼叫時,發現返回的是生成器物件

為了拿到資料,我們應該怎麼做呢?

小紅:老師,是不是可以試試next()函式呢?

對,不過在此之前,我們先要用一個變數去接收這個生成器物件

並且為了觀察生成器的特點,我們對函式進行修改!

仔細看好:

當我們使用next(a)對生成器操作一次時,會返回迴圈一次的值

也就是在yield處結束本次執行

但它的特點就是下次使用next(a)時,接著上次的斷點繼續執行,直到下一個yield

不斷使用next(a),直到執行到生成器結尾處,如下圖:

可能你對他的執行過程還不是特別清晰

我們加上print輸出來徹底搞懂他的執行過程:

發現每次返回值都是在yield的地方了吧~

總結

0.講了兩種生成器建立方式

1.加了yield的函式就變成了生成器

2.要定義一個變數接收生成器的返回值

3.使用next()獲取生成器每次返回的值,並且斷點在yield處

4.下次使用next()從上次的斷電往下執行,直到生成器末端(這裡表現為迴圈結束)

5.生成器屬於迭代器,所以肯定是可迭代物件啦~