文章

第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 暫停和繼續函數的執行。
  • 生成器的應用:學會使用生成器來處理大數據集、流式資料以及無限序列。
  • 生成器表達式:掌握如何使用生成器表達式來高效地處理資料。

任務

  1. 創建一個迭代器類別 EvenNumbers,生成一個範圍內的偶數。
  2. 使用生成器寫一個函數 even_generator(n),生成從 0 到 n 的所有偶數。
  3. 實作一個生成器函數 read_file_line_by_line,逐行讀取一個大檔案,而不是一次性將整個檔案載入記憶體。
  4. 使用生成器表達式來創建一個序列,其中每個數字都是 0 到 10 之間的數字的平方。
本文章以 CC BY 4.0 授權