徹底理解 Python 生成器


1. 生成器定義

在Python中,一邊循環一邊計算的機制,稱為生成器:generator。

 

2. 為什么要有生成器

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

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

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

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

 

3.如何創建生成器

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

>>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630>

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

 

方法二, 如果一個函數中包含yield關鍵字,那么這個函數就不再是一個普通函數,而是一個generator。調用函數就是創建了一個生成器(generator)對象。

 

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表達式整體的結果

  ——換句話說,就是send可以強行修改上一個yield表達式值。比如函數中有一個yield賦值,a = yield 5,第一次迭代到這里會返回5,a還沒有賦值。第二次迭代時,使用.send(10),那么,就是強行修改yield 5表達式的值為10,本來是5的,那么a=10

 

感受下yield返回值的過程(關注點:每次停在哪,下次又開始在哪)及send()傳參的通訊過程,

思考None是如何產生的(第一次取值:yield 返回了 i 值 0,停在yield i,temp沒賦到值。第二次取值,開始在print,temp沒被賦值,故打印None,i加1,繼續while判斷,yield  返回了 i 值 1,停在yield i):

 

 

 

好了,話不多說,翠花,上栗子:

 1 #encoding:UTF-8 
 2 def yield_test(n):  3     for i in range(n):  4         yield call(i)  5         print("i=",i)  6     print("Done.")  7   
 8 def call(i):  9     return i*2  
10   
11 for i in yield_test(5): 12     print(i,",")

  結果:

>>> 0 , i= 0 2 , i= 1  
4 , i= 2  
6 , i= 3  
8 , i= 4 Done.
>>>

 理解的關鍵在於:下次迭代時,代碼從yield的下一條語句開始執行。

 

 總結:

什么是生成器?

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

 

 

練習題:

def count_down(n): while n >= 0: newn = yield n print('newn', newn) if newn: print('if') n = newn print('n =', n) else: n -= 1 cd = count_down(5) for i in cd: print(i, ',') if i == 5: cd.send(3)

 

結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM