Python 简明教程

Python - Generators

Python Generators

Python 中的生成器是创建迭代器的便捷方式。它们允许我们对值序列进行迭代,这意味着值是动态生成的,而不是存储在内存中,这对于大型数据集或无限序列尤其有用。

Python 中的生成器是一种返回迭代器对象的特殊函数类型。它看上去类似于普通 Python 函数,其定义也以 def 关键字开头。但是,生成器在结尾处使用 yield 关键字,而不是使用 return 语句。

Syntax

以下是 generator() 函数的语法 -

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

Creating Generators

在 python 中主要有两种创建生成器的方法 -

  1. Using Generator Functions

  2. Using Generator Expressions

Using Generator Functions

生成器函数使用 '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

Using Generator Expressions

生成器表达式提供了创建生成器的简洁方法。它们使用类似于生成器表达式的语法,但使用括号即 “{}” 代替方括号即 “[]”

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

for value in gen_expr:
    print(value)
1
4
9
16
25

Exception Handling in Generators

我们可以使用带有异常处理的 'while' 循环创建生成器并对其进行遍历,以应对 'StopIteration' 异常。以下代码中的函数是一个生成器,可连续产生 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

Output

1
2
3
4
5

Normal function vs Generator function

Python 中的普通函数和生成器函数具有不同的用途,并表现出不同的行为。了解它们之间的差异对于有效地在我们的代码中利用它们至关重要。

普通函数在被调用时计算并返回一个值或一组值,无论是在列表还是元组中。一旦返回,函数将执行完毕,所有局部变量都会被丢弃,而生成器函数会通过在每次 yield 之间暂停并恢复其状态来一次生成一个值。它使用 yield 语句,而不是 return 语句。

Example

在本例中,我们创建一个普通函数并构建一个 Fibonacci 数列表,然后使用循环遍历该列表 -

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)

Output

1
2
3
5
8

Example

在上面的示例中,我们使用普通函数创建了一个 Fibonacci 数列。当我们要将所有 Fibonacci 数列数字收集到一个列表中时,再使用循环遍历该列表。假设我们希望 Fibonacci 数列达到一个大数。

在这样的情况下,必须将所有数字收集到一个列表中,这需要占用大量的内存。这就是生成器发挥作用的地方,因为它在列表中生成一个数字并将其提供供使用。以下代码是基于生成器的 Fibonacci 数列解决方案 -

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

Asynchronous Generator

异步生成器是一个返回异步迭代器的协程。协程是由 async 关键字定义的 Python 函数,它可以调度并等待其他协程和任务。

与普通生成器一样,异步生成器在每次调用 anext() 函数时(而不是 next() 函数)在迭代器中生成增量项。

Syntax

以下是异步生成器的语法 -

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

Example

以下代码演示了一个协程生成器,该生成器在 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())

Output

1
2
3
4
5

Example

现在,让我们编写一个 Fibonacci 数的异步生成器。为了在协程内部模拟一些异步任务,程序会在生成下一个数字之前调用 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())

Output

1
2
3
5
8