標籤:python generator 迭代 產生器 yield next(obj) next(o)
# 產生器# 通過列表產生式,我們可以直接建立一個列表# 但是,受到記憶體限制,列表容量肯定是有限的# 建立一個100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了# 如果列表元素可以按照某種演算法推算出來,那我們可以在迴圈的過程中不斷推算出後續的元素,這樣就不必建立完整的list,從而節省大量的空間# Python中,這種一邊迴圈一邊計算的機制,稱為產生器:generatorfrom collections import Iterable# 建立一個listL = [x * x for x in range(10)]print(‘L:‘, L)# 建立一個generatorg = (x * x for x in range(10))print(‘g:‘, g)# 建立L和g的區別僅在於最外層的[]和(),L是一個list,而g是一個generator# 使用for列印generator的每一個元素,因為generator是可迭代對象print(‘查看g是否可迭代:‘, isinstance(g, Iterable))for n in g: print(n)# 用函數列印斐波那契數列(用列表產生式寫不出來)def fib(max): l = [] n, a, b = 0, 0, 1 while n < max: l.append(b) a, b = b, a + b n = n + 1 return lprint(‘fib(10):‘, fib(10))# 把fib函數變成generator,只需把print(b)改為yield b就可以了def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1print(‘fib(20) for generator:‘, fib(10))fibList = []for e in fib(10): fibList.append(e)print(‘fibList:‘, fibList)# 如果一個函數定義中包含yield關鍵字,那麼這個函數就不再是一個普通函數,而是一個generator# generator和函數的執行順序不一樣# 函數是順序執行,遇到return語句或者最後一行就返回# 而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行# 定義一個generator,依次返回數字1,3,5:def odd(): print(‘step 1‘) yield 1 print(‘step 2‘) yield 3 print(‘step 3‘) yield 5# 在調用generator時,首先要產生一個generator對象,然後用next()函數不斷獲得下一個傳回值o = odd()print(next(o))print(next(o))print(next(o))# StopIteration# print(next(o))# 可以看到,odd不是普通函數,而是generator,在執行過程中,遇到yield就中斷,下次又繼續執行# 執行3次yield後,已經沒有yield可以執行了,所以,第4次調用next(o)就會報錯# 回到fib的例子,我們在迴圈過程中不斷調用yield,就會不斷中斷。當然要給迴圈設定一個條件來退出迴圈,不然就會產生一個無限數列出來# 同樣的,把函數改成generator後,我們基本上從來不會用next來擷取下一個傳回值,而是直接使用for迴圈來迭代
Python---產生器