Python生成器介紹(原理+實踐)


本篇博文講解生成器,主要介紹2個方面,其一為原理,其二為完整代碼運行及注解說明。

一.生成器原理

生成器卻不同,它可以實現在迭代的同時生成元素。

也就是說,對於可以用某種算法推算得到的多個數據,生成器並不會一次性生成它們,而是什么時候需要,才什么時候生成。

不僅如此,生成器的創建方式也比迭代器簡單很多,大體分為以下 2 步:

  1. 定義一個以 yield 關鍵字標識返回值的函數;
  2. 調用剛剛創建的函數,即可創建一個生成器;

舉個例子:

  1. def intNum():
  2. print("開始執行")
  3. for i in range(5):
  4. yield i
  5. print("繼續執行")
  6. num = intNum()

由此,我們就成功創建了一個 num 生成器對象。顯然,和普通函數不同,number() 函數的返回值用的是 yield 關鍵字,而不是 return 關鍵字,此類函數又成為生成器函數。

和 return 相比,yield 除了可以返回相應的值,還有一個更重要的功能,即每當程序執行完該語句時,程序就會暫停執行。不僅如此,即便調用生成器函數,Python 解釋器也不會執行函數中的代碼,它只會返回一個生成器(對象)。

要想使生成器函數得以執行,或者想使執行完 yield 語句立即暫停的程序得以繼續執行,有以下 2 種方式:

  1. 通過生成器(上面程序中的 num)調用 next() 內置函數或者 __next__() 方法;
  2. 通過 for 循環遍歷生成器。

例如,在上面程序的基礎上,添加如下語句:

  1. #調用 next() 內置函數
  2. print(next(num))
  3. #調用 __next__() 方法
  4. print(num.__next__())
  5. #通過for循環遍歷生成器
  6. for i in num:
  7. print(i)

程序執行結果為:

開始執行
0
繼續執行
1
繼續執行
2
繼續執行
3
繼續執行
4
繼續執行

這里有必要給讀者分析一個程序的執行流程:
1) 首先,在創建有 num 生成器的前提下,通過其調用 next() 內置函數,會使 Python 解釋器開始執行 intNum() 生成器函數中的代碼,因此會輸出“開始執行”,程序會一直執行到yield i,而此時的 i==0,因此 Python 解釋器輸出“0”。由於受到 yield 的影響,程序會在此處暫停。

2) 然后,我們使用 num 生成器調用 __next__() 方法,該方法的作用和 next() 函數完全相同(事實上,next() 函數的底層執行的也是 __next__() 方法),它會是程序繼續執行,即輸出“繼續執行”,程序又會執行到yield i,此時 i==1,因此輸出“1”,然后程序暫停。

3) 最后,我們使用 for 循環遍歷 num 生成器,之所以能這么做,是因為 for 循環底層會不斷地調用 next() 函數,使暫停的程序繼續執行,因此會輸出后續的結果。

注意,在 Python 2.x 版本中不能使用 __next__() 方法,可以使用 next() 內置函數,另外生成器還有 next() 方法(即以 num.next() 的方式調用)。


除此之外,還可以使用 list() 函數和 tuple() 函數,直接將生成器能生成的所有值存儲成列表或者元組的形式。例如:

  1. num = intNum()
  2. print(list(num))
  3. num = intNum()
  4. print(tuple(num))

程序執行結果為:

開始執行
繼續執行
繼續執行
繼續執行
繼續執行
繼續執行
[0, 1, 2, 3, 4]
開始執行
繼續執行
繼續執行
繼續執行
繼續執行
繼續執行
(0, 1, 2, 3, 4)

通過輸出結果可以判斷出,list() 和 tuple() 底層實現和 for 循環的遍歷過程是類似的。

相比迭代器,生成器最明顯的優勢就是節省內存空間,即它不會一次性生成所有的數據,而是什么時候需要,什么時候生成。

 

 

二.完整代碼說明:

# 帶有參數的生成器,參數為k
def intNum(k):
print("開始執行")
n=0
while n<4:
n=n+1
yield n+5+k
print("繼續執行")
num = intNum(3)
# 說明參數k=3保持不變,每次迭代都不會改變,
# 而n將會在每次迭代中一直+1,當n<10滿足條件
# 就終止迭代。
for i in num:
# 這里i是num函數返回的值,即n+5+k
print(i)
# 注:第一運行將執行wile上面的代碼,隨后在yield處停止,
# 當再次迭代時將執行yield后面的代碼(print("繼續執行")),
# 然后在從while處執行直到遇到yield后,又重復上述步驟執行

運行結果:

 

 

 

原理主要借鑒(很詳細):http://c.biancheng.net/view/2393.html

 


免責聲明!

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



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