Python - 產生器:初學者的溫柔介紹

你好,有志成為 Python 程式設計師的人!今天,我們將進入 Python 產生器的精彩世界。如果你之前從未聽過它們,不必擔心 - 我們會從頭開始,逐步學習。在這個教程結束時,你將能像專家一樣創建產生器!

Python - Generators

Python 產生器是什麼?

想象一下,你正在閱讀一本非常厚的書。你可以一次複印整本書(這將浪費很多紙張!),也可以一次讀一頁。這就是 Python 中產生器的工作原理!

產生器是一種特殊的函數,它允許我們隨著時間生成一系列值,而不是一次計算所有值並將它們存儲在記憶體中。它們就像魔法工廠一樣,按需生成值。

為什麼使用產生器?

  1. 記憶體效率:產生器對記憶體友好。它們不會一次將所有值存儲在記憶體中。
  2. 效能:它們可以改善你的代碼效能,尤其是處理大型數據集時。
  3. 簡潔:產生器可以使你的代碼更清晰、更易讀。

讓我們深入了解它們是如何工作的!

創建產生器

在 Python 中創建產生器主要有兩種方法:

  1. 使用產生器函數
  2. 使用產生器表達式

產生器函數

產生器函數看起來就像普通函數一樣,但使用 yield 關鍵字而不是 return。以下是一個簡單的例子:

def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1

# 使用我們的產生器
for number in count_up_to(5):
print(number)

輸出:

1
2
3
4
5

在這個例子中,count_up_to 是一個產生器函數。每次它產生一個值時,它都會暫停其執行並記住其狀態。下次調用它時,它會從上次離開的地方繼續。

產生器表達式

產生器表達式就像列表解析,但使用括號而不是方括號。它們是創建產生器的簡潔方式。以下是一個例子:

# 產生器表達式
squares = (x**2 for x in range(5))

# 使用我們的產生器
for square in squares:
print(square)

輸出:

0
1
4
9
16

這個產生器表達式即時創建一個平方數的序列,而不會一次將它們全部存儲在記憶體中。

產生器中的異常處理

產生器也可以處理異常,這非常酷!以下是一個例子:

def div_generator(a, b):
try:
result = a / b
yield result
except ZeroDivisionError:
yield "不能除以零!"

# 使用我們的產生器
g = div_generator(10, 2)
print(next(g))  # 輸出:5.0

g = div_generator(10, 0)
print(next(g))  # 輸出:不能除以零!

在這個例子中,我們的產生器在嘗試除以零時优雅地處理了情況。

普通函數與產生器函數

讓我們比較一個普通函數和一個產生器函數來看看差異:

# 普通函數
def get_squares(n):
squares = []
for i in range(n):
squares.append(i**2)
return squares

# 產生器函數
def gen_squares(n):
for i in range(n):
yield i**2

# 使用普通函數
print(get_squares(5))  # 輸出:[0, 1, 4, 9, 16]

# 使用產生器函數
for square in gen_squares(5):
print(square)  # 每個平方數在新的一行上打印

主要差異在於:

  1. 記憶體使用:普通函數一次創建並存儲所有值,而產生器一次生成一個值。
  2. 語法:普通函數使用 return,而產生器使用 yield
  3. 迭代:可以 直接迭代產生器,而普通函數的結果需要先存儲在變量中。

非同步產生器

Python 3.6 引入了非同步產生器,它們就像普通產生器一樣,但用於非同步編程。它們使用 async defyield

import asyncio

async def async_gen():
for i in range(3):
await asyncio.sleep(1)
yield i

async def main():
async for item in async_gen():
print(item)

asyncio.run(main())

這個例子模擬了一個隨時間產生值的非同步操作。

產生器方法

產生器有一些特殊的 方法可以非常有用。以下是最常見的一些:

方法 描述
next() 從產生器中检索下一個項目
send() 將值傳入產生器
throw() 在產生器中拋出異常
close() 關閉產生器

以下是一個使用 send() 的快速示例:

def echo_generator():
while True:
received = yield
print(f"Received: {received}")

g = echo_generator()
next(g)  # 創建產生器
g.send("Hello")  # 輸出:Received: Hello
g.send("World")  # 輸出:Received: World

就是這樣!你剛剛走出了 Python 產生器的精彩世界的第一步。記住,練習成就完美,所以不要害怕嘗試這些概念。在你意識到之前,你將會在 Python 程式中使用產生器來解決各種有趣的問題。編程愉快!

Credits: Image by storyset