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
# 使用生成器
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
生成器中的异常处理
我们可以使用 while 循环和针对 StopIteration 异常的异常处理来创建并迭代生成器。下面代码中的函数是一个生成器,它依次 yield 从 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
普通函数 vs 生成器函数
Python 中的普通函数和生成器函数用途不同,行为也各异。理解它们的区别对于在代码中有效利用它们至关重要。
普通函数在调用时计算并返回单个值或一组值(例如列表或元组)。一旦返回,函数执行结束,所有局部变量被丢弃;而生成器函数通过在每个 yield 之间暂停和恢复其状态,一次 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() 函数)时,在迭代器中 yield 增量项。
语法
以下是异步生成器的语法 −
async def generator(): . . . . . . yield obj it = generator() anext(it) . . .
示例
以下代码演示了一个协程生成器,在每次 async for 循环迭代时 yield 递增整数。
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
示例
现在让我们为斐波那契数编写一个异步生成器。为了模拟协程内部的一些异步任务,程序在 yield 下一个数字之前调用 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