iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0

第二十天:Python 中的生成器(Generators)與迭代器(Iterators)

內容概述:

今天我們將探討兩個強大且常見的 Python 特性——生成器(Generators)迭代器(Iterators)。這兩個概念在處理大量資料或實現延遲評估(Lazy Evaluation)時非常有用。生成器可以視為一種特殊的迭代器,它能夠動態生成數據,而不是一次性生成所有結果,這在節省記憶體方面特別有效。


一、什麼是迭代器(Iterators)?

迭代器是一種允許你逐個訪問其元素的物件。在 Python 中,任何實現了 __iter__()__next__() 方法的物件都被認為是迭代器。迭代器的核心在於它「懶惰地」一次生成一個元素,而不會一次生成全部元素。

範例:如何創建自己的迭代器
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:
            self.current += 1
            return self.current - 1
        else:
            raise StopIteration

# 使用迭代器
counter = Counter(1, 5)
for num in counter:
    print(num)

輸出結果:

1
2
3
4
5

在這個範例中,我們創建了一個名為 Counter 的迭代器類,它逐次輸出從 startend 之間的數字。


二、什麼是生成器(Generators)?

生成器是 Python 中一種特殊的迭代器,與普通函數不同,它使用 yield 關鍵字來返回值,而不是 return。生成器能夠一次生成一個值,並且在下一次調用時,會從上次返回的地方繼續執行。這種特性使得生成器非常適合處理大型數據集或需要動態生成數據的場景。

範例:創建生成器
def count_up_to(max_num):
    num = 1
    while num <= max_num:
        yield num
        num += 1

# 使用生成器
for number in count_up_to(5):
    print(number)

輸出結果:

1
2
3
4
5

與迭代器不同,生成器的最大優勢是它更加簡潔且節省記憶體。當我們不需要一次生成所有數據時,生成器是最佳選擇。


三、生成器與列表的差異

生成器與列表有很多相似之處,因為它們都可以被迭代。然而,最大的區別在於生成器不會一次性生成所有結果,而是根據需要動態生成數據。這使得生成器在處理大規模數據時,效率要高得多。

範例:生成器 VS 列表
# 使用列表一次生成所有結果
numbers = [i for i in range(1, 1000000)]

# 使用生成器
def generate_numbers(max_num):
    for i in range(1, max_num):
        yield i

numbers_generator = generate_numbers(1000000)

在這個範例中,列表會在記憶體中一次性生成 100 萬個數字,而生成器僅在需要時才生成數字,因此在記憶體使用上,生成器更具優勢。


四、生成器表達式

生成器還可以使用類似於列表生成式的語法,稱為生成器表達式。生成器表達式語法更加簡潔,並且與列表生成式不同,它不會一次性將所有元素保存在記憶體中。

範例:生成器表達式
numbers = (x * x for x in range(1, 6))

for number in numbers:
    print(number)

輸出結果:

1
4
9
16
25

在這個範例中,我們使用生成器表達式創建了一個可以輸出平方數的生成器。這種語法與列表生成式幾乎相同,唯一不同的是,生成器使用的是小括號 ( ) 而不是方括號 [ ]


五、生成器的應用場景

生成器非常適合處理大型數據集或需要動態生成的場景。以下是幾個常見的應用場景:

  1. 處理大型文件
    生成器可以逐行讀取文件,而不必一次性將整個文件加載到記憶體中。

    def read_large_file(file_path):
        with open(file_path, 'r') as file:
            for line in file:
                yield line.strip()
    
    for line in read_large_file('large_file.txt'):
        print(line)
    
  2. 無限序列
    生成器可以輕鬆生成無限序列,這對於需要無限循環或大量數據時特別有用。

    def infinite_sequence():
        num = 1
        while True:
            yield num
            num += 1
    
    for number in infinite_sequence():
        if number > 5:
            break
        print(number)
    

六、練習與實作

練習 1:
  • 編寫一個生成器函數來生成 1 到 10 的平方數,並將其打印出來。
練習 2:
  • 寫一個生成器表達式來產生 1 到 100 之間所有偶數的平方。
練習 3:
  • 編寫一個迭代器類,它可以生成 Fibonacci 序列的前 n 個數字。

這些練習旨在幫助你掌握 Python 中的生成器和迭代器。生成器和迭代器是用來處理大型數據集合或需要逐步生成值的情況下的強大工具。以下是每個練習的詳細說明和範例代碼。


練習 1:編寫一個生成器函數來生成 1 到 10 的平方數
步驟:
  1. 定義一個生成器函數,使用 yield 關鍵字來逐步生成 1 到 10 的平方數。
  2. 使用 for 迴圈來打印每個平方數。
範例代碼:
# 定義生成器函數
def square_numbers():
    for i in range(1, 11):
        yield i ** 2  # 使用 yield 生成平方數

# 使用生成器
for square in square_numbers():
    print(square)
解釋:
  • yield:用來返回一個值,但函數不會結束,而是會在下一次迴圈時繼續執行。
  • 這個生成器會逐一生成 1 到 10 的平方數。

練習 2:寫一個生成器表達式來產生 1 到 100 之間所有偶數的平方
步驟:
  1. 使用生成器表達式來生成 1 到 100 之間所有偶數的平方。
  2. 使用 for 迴圈來打印這些數字。
範例代碼:
# 使用生成器表達式來生成 1 到 100 之間所有偶數的平方
even_squares = (x ** 2 for x in range(1, 101) if x % 2 == 0)

# 打印每個平方數
for square in even_squares:
    print(square)
解釋:
  • 生成器表達式:與列表生成式類似,但不會一次性生成所有結果,而是每次迭代時生成一個值,節省內存。
  • 這裡只生成 1 到 100 之間的偶數平方數。

練習 3:編寫一個迭代器類,它可以生成 Fibonacci 序列的前 n 個數字
步驟:
  1. 創建一個類來表示 Fibonacci 序列的迭代器。
  2. 在這個類中定義 __iter__()__next__() 方法來實現 Fibonacci 數列的生成。
範例代碼:
# 定義 Fibonacci 迭代器類
class Fibonacci:
    def __init__(self, n):
        self.n = n  # 設定要生成的數列長度
        self.current = 0  # 初始化當前 Fibonacci 數列的位置
        self.a, self.b = 0, 1  # 定義 Fibonacci 序列的初始值
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.n:
            value = self.a
            self.a, self.b = self.b, self.a + self.b  # 更新 a 和 b 的值
            self.current += 1
            return value
        else:
            raise StopIteration  # 當生成完 n 個數字時結束迭代

# 使用 Fibonacci 迭代器來生成前 n 個 Fibonacci 數字
n = int(input("請輸入要生成的 Fibonacci 數列的數量: "))
fibonacci_sequence = Fibonacci(n)

for number in fibonacci_sequence:
    print(number)
解釋:
  • __iter__():返回自身作為迭代器對象。
  • __next__():返回當前的 Fibonacci 數字,並更新數列的值。當達到指定的 n 時,拋出 StopIteration 來結束迭代。
  • 用戶輸入 n 後,該迭代器會生成 Fibonacci 序列的前 n 個數字。

這些練習展示了生成器和迭代器的應用,包括如何用生成器逐步產生數字序列,使用生成器表達式來優化資源,以及使用迭代器來控制序列的生成。

總結

生成器和迭代器是 Python 中處理大量數據的高效工具。它們允許我們根據需要動態生成數據,而不是一次性加載所有數據,從而節省了記憶體。生成器不僅使程式碼更加簡潔,還提高了程式的性能,特別是在處理大規模數據時。


上一篇
跟著 ChatGPT成為程式大佬!Python 中的裝飾器(Decorators)
下一篇
跟著 ChatGPT成為程式大佬!Python 中的異步程式設計(Asynchronous Programming)
系列文
如果讓chatgpt參加iThome鐵人賽,他竟然寫出...!?31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言