產生器/生成器 Generators
Generator 是一種特殊的迭代器,使用 yield 關鍵字生成值,而不是一次性返回所有值。Generator能夠在執行過程中暫停,保留當前狀態,並在下一次被調用時繼續執行。生成器以lazy loading (惰性加載) 的方式處理數據,適合處理需要大量記憶體的數據流或無限序列。
lazy loading (惰性加載) : 惰性加載是一種優化策略,指的是僅在需要時才加載或初始化資源,而非在程序啟動時就一次性加載所有內容。這種方法可以減少記憶體使用和提升應用啟動速度,特別適合處理大量數據或昂貴的操作。
以下會介紹幾種Generator的使用方式
- 生成 1 到 n 的平方數,定義square_numbers函數做為一個Generator Function,yield則是generator的關鍵,他與return差異在於
- return: 整支function執行完回傳對應結果
- yield: function執行到這行會執行完回傳當下的值,以下例來說,會回傳 i ** 2,e.g. i的平方
所以在下面例子,我是在產生器函數Generator Function傳入5也就是會產生1~5的平方回傳並賦值給square。
執行順序為
- 傳入5作為Generator Function參數
- for迴圈內會執行 i = 1,計算1的平方,執行yield 1回傳1並且暫停函數
- 產生器函數回傳值的1放入square
- 這時因為python會自動在for迴圈引入next()函數,此函數會自動被執行至完整執行完生成器函數的結果。
- next()函數會直接讓i=2繼續執行,因此yield返回值是4,存入square,並印出來
- 依序執行i = 3, 4, ,5直到停止條件
def square_numbers(n): for i in range(1, n + 1): yield i**2 for square in square_numbers(5): print(square) |
- 生成費波那契數列 (Fibonacci Sequence): 產生器的特性能很好的產生費式數列,由於yield函數,我們可以耗費較少記憶體還計算費式數列
for裡面的"_"在python裡代表的是不需要使用的變數,然後一樣fibonacci產生器函數,a, b = 0, 1為python 可以使用的語法,代表0賦值給a,1賦值給b,下面a,b = b, a + b也是同理。
在fibonacci產生器函數中的執行順序,6作為產生器函數的傳入參數,代表在產生器裡要執行6次,那對應結果是
a = 0, b = 1 -> 執行yield a並且返回函數,賦值給num,印出num
for迴圈自動執行next()函數,從yield函數開始往下執行。
a = b, b = a + b -> a = 1, b = 0 + 1,yield a = 1,賦值給num並印出
照此流程依序會執行
a = 1, b = 1 + 1 = 2
a = 2, b = 1 + 2 = 3
a = 3, b = 2 + 3 = 5
a = 5, b = 3 + 5 = 8
a = 8, b = 5 + 8 = 13
def fibonacci(n): a, b = 0, 1 for _ in range(n): yield a a, b = b, a + bfor num in fibonacci(6): print(num) |
這麼一來我們可以不用宣告一堆記憶體空間來儲存數列,便可以動態配置空間來傳遞參數。
- 產生5個質數: 接下來的應用也類似就不每個步驟解析了,利用質數的判斷式來寫
def is_prime(num): if num < 2: return False for i in range(2, int(num**0.5) + 1): if num % i == 0: return False return True def prime_numbers(n): count = 0 num = 2 while count < n: if is_prime(num): yield num count += 1 num += 1for prime in prime_numbers(5): print(prime) |
目前還沒感受到Generator的強大之處,不過會被設計出來一定有他的理由,可能目前還沒碰到大型專案,對於記憶體配置比較沒有要求。希望以後能有機會看看在大型專案上這些東西是怎麼被應用的。
