《利用python進行數據分析》——3.2函數——生成器generator——讀書筆記

1. 生成器定義

一邊循環一邊計算的機制,稱爲:生成器(generator)

生成器(generator)是構造新的可迭代對象的一種簡單方式。

一般的函數執行之後只會返回單個值,而生成器則是以延遲的方式返回一個值序列,

即每返回一個值之後暫停,直到下一個值被請求時再繼續。

生成器是一個返回迭代器的函數,只能用於迭代操作,更簡單點理解生成器就是一個迭代器

2. 爲什麼要有生成器

python生成器的優點:

(1)延遲計算,一次返回一個結果。生成器不會一次生成所有的結果,而是一邊循環一邊計算,這對於大數據量處理,是個非常有用的優勢。因爲在編程的實際應用中,佔用內存量是工程師必須考慮的一個問題。

列表所有數據都在內存中,如果有海量數據的話將會非常耗內存。

如:僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。

如果列表元素按照某種算法推算出來,那我們就可以在循環的過程中不斷推算出後續的元素,這樣就不必創建完整的list,從而節省大量的空間。

簡單一句話:我又想要得到龐大的數據,又想讓它佔用空間少,那就用生成器!

(2)有效提高代碼可讀性。使用生成器以後,代碼行數更少。

 

3.如何創建生成器

第一種方法很簡單,只要把一個列表生成式的[]改成(),就創建了一個generator:

In [189]: gen = (x ** 2 for x in range(100))
In [190]: gen
Out[190]: <generator object <genexpr> at 0x1022ef630>

 創建Lg的區別僅在於最外層的[]()L是一個list,而g是一個generator。

方法二, 如果一個函數中包含yield關鍵字,那麼這個函數就不再是一個普通函數,而是一個generator。調用函數就是創建了一個生成器(generator)對象。要創建一個生成器,只需將函數中的return替換爲yeild即可:

def _make_gen():
    for x in range(100):
        yield x ** 2
gen = _make_gen()

生成器表達式也可以取代列表推導式,作爲函數參數:

In [191]: sum(x ** 2 for x in range(100))
Out[191]: 328350
In [192]: dict((i, i **2) for i in range(5))
Out[192]: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

4. 生成器的工作原理

(1)生成器(generator)能夠迭代的關鍵是它有一個next()方法,

  工作原理就是通過重複調用next()方法,直到捕獲一個異常。

(2)帶有 yield 的函數不再是一個普通函數,而是一個生成器generator。

  可用next()調用生成器對象來取值。next 兩種方式 t.__next__()  |  next(t)。

  可用for 循環獲取返回值(每執行一次,取生成器裏面一個值)

  (基本上不會用next()來獲取下一個返回值,而是直接使用for循環來迭代)。

(3)yield相當於 return 返回一個值,並且記住這個返回的位置,下次迭代時,代碼從yield的下一條語句開始執行。

(4).send() 和next()一樣,都能讓生成器繼續往下走一步(下次遇到yield停),但send()能傳一個值,這個值作爲yield表達式整體的結果

  通過例子來理解下:

In [63]: def yield_test(n):
 (1)...:     print("begin:")
 (2)...:     for i in range(n):
 (3)...:         print('yield_1_i=',i)
 (4)...:         yield call(i)
 (5)...:         print('yield_2_i=',i)
 (6)...:     print("Done")
    ...:
In [64]: def call(i):
 (7)...:     print('call',i)
 (8)...:     return i*2
    ...:
In [65]: for i in yield_test(3):
 (9)...:     print("now:",i)

yield相當於 return 返回一個值,並且記住這個返回的位置,
下次迭代時,代碼從yield的下一條語句開始執行。

結果:
begin           (運行9)
yield_1_i=0     (進入第一輪for循環,i=0,運行3)       
call 0          (運行4——7——8,得到0*2=0,返回0)
now 0           (yield相當於return返回一個值,並且記住這個返回的位置,所以運行9)
yield_2_i=0     (下次迭代時,代碼從yield的下一條語句開始執行,所以運行5,i不變仍然是0)
yield_1_i=1     (進入第二輪for循環,i=1,運行3)
call 1          (運行4——7——8,得到1*2=2,返回2)
now 2           (yield相當於return返回一個值,並且記住這個返回的位置,所以運行9)
yield_2_i=1     (下次迭代時,代碼從yield的下一條語句開始執行,所以運行5,i仍是1)
yield_1_i=2     (進入第三輪for循環,i=2,運行3)
call 2          (運行4——7——8,得到2*2=4,返回4)
now 4           (yield相當於return返回一個值,並且記住這個返回的位置,所以運行9)
yield_2_i=2     (下次迭代時,代碼從yield的下一條語句開始執行,所以運行5,i仍是2)
done            (循環結束,運行6)

   

 總結:

什麼是生成器?

生成器僅僅保存了一套生成數值的算法,並且沒有讓這個算法現在就開始執行,而是我什麼時候調它,它什麼時候開始計算一個新的值,並給你返回。

 

 

參考:https://www.cnblogs.com/liangmingshen/p/9706181.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章