Python - 生成器



Python 生成器

Python 中的生成器是建立迭代器的一種便捷方式。它們允許我們迭代一系列值,這意味著值是動態生成的,而不是儲存在記憶體中,這對於大型資料集或無限序列特別有用。

Python 中的生成器是一種特殊的函式,它返回一個迭代器物件。它看起來類似於普通的 Python 函式,其定義也以 def 關鍵字開頭。但是,它不像普通函式那樣在結尾使用 return 語句,而是使用 yield 關鍵字。

語法

以下是 **generator()** 函式的語法:

def generator():
 . . .
 . . .
 yield obj
it = generator()
next(it)
. . .

建立生成器

在 Python 中建立生成器主要有兩種方法:

  • 使用生成器函式
  • 使用生成器表示式

使用生成器函式

生成器函式使用 'yield' 語句一次返回所有值。每次呼叫生成器的 **__next__()** 方法時,生成器都會從上次 yield 語句之後的地方恢復執行。以下是如何建立生成器函式的示例。

def count_up_to(max_value):
    current = 1
    while current <= max_value:
        yield current
        current += 1

# Using the generator
counter = count_up_to(5)
for number in counter:
    print(number)

輸出

1
2
3
4
5

使用生成器表示式

生成器表示式提供了一種簡潔的建立生成器的方法。它們使用類似於列表推導式的語法,但使用圓括號 () 而不是方括號 []。

gen_expr = (x * x for x in range(1, 6))

for value in gen_expr:
    print(value)

輸出

1
4
9
16
25

生成器中的異常處理

我們可以建立一個生成器,並使用帶有 'StopIteration' 異常處理的 'while' 迴圈來迭代它。下面程式碼中的函式是一個生成器,它連續地產生從 1 到 5 的整數。

呼叫此函式時,它返回一個迭代器。每次呼叫 **next()** 方法都會將控制權轉移回生成器並獲取下一個整數。

def generator(num):
   for x in range(1, num+1):
      yield x
   return
   
it = generator(5)
while True:
   try:
      print (next(it))
   except StopIteration:
      break

輸出

1
2
3
4
5

普通函式與生成器函式

Python 中的普通函式和生成器函式服務於不同的目的,並表現出不同的行為。理解它們的區別對於有效地利用它們至關重要。

普通函式在被呼叫時計算並返回單個值或一組值(在列表或元組中)。一旦返回,函式的執行就完成了,所有區域性變數都被丟棄;而生成器函式每次產生一個值,並在每次 yield 之間暫停和恢復其狀態。它使用 yield 語句而不是 return 語句。

示例

在這個例子中,我們建立一個普通函式,構建一個斐波那契數列的列表,然後使用迴圈迭代該列表:

def fibonacci(n):
   fibo = []
   a, b = 0, 1
   while True:
      c=a+b
      if c>=n:
         break
      fibo.append(c)
      a, b = b, c
   return fibo
f = fibonacci(10)
for i in f:
   print (i)

輸出

1
2
3
5
8

示例

在上面的例子中,我們使用普通函式建立了斐波那契數列。當我們想將所有斐波那契數列的數字收集到一個列表中,然後使用迴圈遍歷該列表時。想象一下,如果我們想要一個很大的斐波那契數列。

在這種情況下,所有數字都必須收集到一個列表中,這需要大量的記憶體。這就是生成器有用的地方,因為它一次生成列表中的一個數字並提供使用。以下程式碼是基於生成器的斐波那契數列解決方案:

def fibonacci(n):
   a, b = 0, 1
   while True:
      c=a+b
      if c>=n:
         break
      yield c
      a, b = b, c
   return
   
f = fibonacci(10)
while True:
   try:
      print (next(f))
   except StopIteration:
      break 

輸出

1
2
3
5
8

非同步生成器

非同步生成器是一個返回非同步迭代器的協程。協程是一個用async關鍵字定義的Python函式,它可以排程和等待其他協程和任務。

就像普通的生成器一樣,非同步生成器在每次呼叫anext()函式(而不是next()函式)時都會在迭代器中產生增量項。

語法

以下是非同步生成器的語法:

async def generator():
. . .
. . .
yield obj
it = generator()
anext(it)
. . .

示例

以下程式碼演示了一個協程生成器,它在async for迴圈的每次迭代中產生遞增的整數。

import asyncio

async def async_generator(x):
   for i in range(1, x+1):
      await asyncio.sleep(1)
      yield i
      
async def main():
   async for item in async_generator(5):
      print(item)
      
asyncio.run(main())

輸出

1
2
3
4
5

示例

現在讓我們為斐波那契數列編寫一個非同步生成器。為了模擬協程內部的一些非同步任務,程式在產生下一個數字之前呼叫sleep()方法持續1秒。結果,我們將在一秒鐘的延遲後看到螢幕上列印的數字。

import asyncio

async def fibonacci(n):
   a, b = 0, 1
   while True:
      c=a+b
      if c>=n:
         break
      await asyncio.sleep(1)
      yield c
      a, b = b, c
   return
   
async def main():
   f = fibonacci(10)
   async for num in f:
      print (num)
      
asyncio.run(main())

輸出

1
2
3
5
8
廣告