第20天:生成器與迭代器
課程簡介
在處理大量資料時,我們可能不希望一次性將所有資料都載入記憶體中。生成器 和 迭代器 是 Python 中處理大量資料或延遲計算的強大工具。生成器允許我們一個一個產生資料,並且只有在需要時才會計算,這節省了記憶體並提高了程式的效能。今天,我們將學習如何使用生成器和迭代器,並了解它們的工作原理及應用。
學習內容
1. 迭代器的基本概念
迭代器 是一個可以逐一返回元素的物件。Python 中的迭代器需實作 __iter__()
和 __next__()
兩個方法:
__iter__()
返回迭代器本身。__next__()
返回下一個元素,當無更多元素時拋出StopIteration
異常。
範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Counter:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current <= self.end:
result = self.current
self.current += 1
return result
else:
raise StopIteration
counter = Counter(1, 5)
for num in counter:
print(num)
輸出結果:
1
2
3
4
5
1
2
3
4
5
在這個範例中,Counter
類別實作了 __iter__()
和 __next__()
方法,讓它能成為一個迭代器,並在每次迭代時返回一個新的值。
2. 生成器的基本概念
生成器 是一種特殊的函數,它使用 yield
關鍵字來返回一個值,而不是 return
。當函數執行到 yield
時,函數的狀態會暫停,並等待下一次呼叫時繼續執行。
範例:
1
2
3
4
5
6
7
def countdown(num):
while num > 0:
yield num
num -= 1
for i in countdown(5):
print(i)
輸出結果:
1
2
3
4
5
5
4
3
2
1
這裡的 countdown
函數在每次迭代時都會返回當前的數值,並在下一次迭代時繼續從 yield
處執行。
3. 生成器與 next()
函數
生成器是一種迭代器,因此我們可以使用 next()
函數來手動獲取生成器的下一個值。
範例:
1
2
3
4
5
6
7
8
9
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # 輸出: 1
print(next(gen)) # 輸出: 2
print(next(gen)) # 輸出: 3
在這裡,我們使用 next()
逐一取得生成器的值,直到耗盡生成器中的所有值。
4. 生成器的應用場景
生成器特別適合處理大量資料或需要延遲計算的場景。以下是一些應用場景:
- 處理大數據集:生成器可以逐一處理數據,避免一次性載入整個數據集,減少記憶體消耗。
- 流式資料處理:生成器可用於處理即時流式資料,像是逐行讀取檔案內容。
- 無限序列:生成器可以用來定義無限序列,如費波那契數列。
範例(費波那契數列生成器):
1
2
3
4
5
6
7
8
9
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
for _ in range(10):
print(next(fib))
輸出結果:
1
2
3
4
5
6
7
8
9
10
0
1
1
2
3
5
8
13
21
34
5. 使用生成器表達式
生成器表達式類似於列表生成式(List Comprehension),但它會返回一個生成器物件,而不是一個列表。這可以讓我們在需要時才生成資料,節省記憶體。
範例:
1
2
3
gen_expr = (x * x for x in range(5))
for val in gen_expr:
print(val)
輸出結果:
1
2
3
4
5
0
1
4
9
16
這裡的 gen_expr
是一個生成器表達式,它逐一計算每個元素的平方值。
教學重點
- 迭代器的概念:理解迭代器如何逐一返回元素,並掌握
__iter__()
和__next__()
方法的實作。 - 生成器的概念:理解生成器如何使用
yield
暫停和繼續函數的執行。 - 生成器的應用:學會使用生成器來處理大數據集、流式資料以及無限序列。
- 生成器表達式:掌握如何使用生成器表達式來高效地處理資料。
任務
- 創建一個迭代器類別
EvenNumbers
,生成一個範圍內的偶數。 - 使用生成器寫一個函數
even_generator(n)
,生成從 0 到 n 的所有偶數。 - 實作一個生成器函數
read_file_line_by_line
,逐行讀取一個大檔案,而不是一次性將整個檔案載入記憶體。 - 使用生成器表達式來創建一個序列,其中每個數字都是 0 到 10 之間的數字的平方。
本文章以 CC BY 4.0 授權