协程之生成器yield from

1. 生成器介绍

生成器是 Python 中非常强大的功能之一,可以帮助我们简化代码结构并提高代码执行效率。当需要生成大量的数据集合时,我们使用生成器来迭代数据,而不是等待所有数据都生成完毕,才开始遍历数据。这样做可以节省大量时间和资源,因为仅当实际需要使用数据集合时,才会生成数据。在 Python 中,生成器有两种创建方式:使用生成器函数和使用生成器表达式。

1.1 使用生成器函数创建生成器

生成器函数是普通函数的一种特殊类型,用于生成迭代器。在函数体内,使用 yield 语句而不是 return 语句来返回结果。当使用 yield 语句时,Python 解释器会自动将函数体内的代码转换成一个生成器,该生成器可以使用迭代器协议来进行迭代。

def my_generator(start, stop):

while start <= stop:

yield start

start += 1

for i in my_generator(1, 5):

print(i)

上述代码中,我们定义了一个生成器函数 my_generator,它接收两个参数 start 和 stop,并通过 yield 语句返回从 start 到 stop 的所有整数。for 循环遍历该生成器迭代器,打印出从 1 到 5 的所有整数。

2. yield from 语法

yield from 语法是 Python 3.3 引入的语法,它可以简化使用生成器的复杂度并提高代码的可读性。在之前的生成器函数中,我们通过使用 yield 语句来传递数据,但是如果我们想要将多个生成器结合在一起使用时,代码会变得非常复杂。这时,我们就可以使用 yield from 来简化代码结构。

2.1 yield from 的使用方式

yield from 的使用方式比较简单,影响到两个方面,即委派生成器和子生成器。它将委派生成器委托给子生成器来执行,并且在子生成器执行完毕后,自动将结果传回给委派生成器。

在使用 yield from 时,可以将委派生成器中的参数提供给子生成器,并且可以在委派生成器中使用 try/except/finally 语句处理子生成器抛出的异常。

def subgenerator():

yield 1

yield 2

yield 3

def my_generator():

yield from subgenerator()

yield 'foo'

for item in my_generator():

print(item)

上述代码中,我们定义了一个子生成器 subgenerator,它通过 yield 语句返回 1,2,3 三个整数。我们定义了一个委派生成器 my_generator,并使用 yield from 语句将 subgenerator 委派给 my_generator 执行,这就等同于让 my_generator 执行 subgenerator 中的代码。在子生成器执行完毕后,自动将返回值 'foo' 传回给委派生成器。

2.2 yield from 的异常处理

在使用 yield from 时,委派生成器可以使用 try/except/finally 语句来处理子生成器可能抛出的异常。在这种情况下,子生成器的异常可以通过委派生成器自动捕获并处理。

def subgenerator():

yield 1

raise ValueError('something wrong')

yield 2

yield 3

def my_generator():

try:

yield from subgenerator()

except ValueError as e:

yield 'error: %s' % e

for item in my_generator():

print(item)

在上述代码中,我们修改了 subgenerator,让它在返回 1 后抛出一个 ValueError 异常。我们通过在 my_generator 中使用 try/except 语句来捕获异常,并将错误信息格式化后通过 yield 语句返回给委派生成器。这样一来,我们可以通过委派生成器来处理子生成器可能抛出的异常。

3. yield from 的优点

yield from 语法具有简化代码结构、提高代码可读性和优化代码执行效率的优点。使用 yield from 不仅可以简化生成器函数的代码结构,而且可以减少内存占用,因为生成器只生成需要返回的数据,而不是一次性生成所有数据。

此外,yield from 还具有可以同时处理多个子生成器的优点。在实际编程过程中,我们可能会需要同时执行多个子任务,并且需要确定子任务执行的顺序。这时,我们可以使用生成器来执行这些子任务,并且使用 yield from 来等待所有子任务执行完成后,再将子任务的返回值汇总。

4. yield from 的应用场景

yield from 语法适用于需要同时执行多个子任务的场景,例如爬虫程序、异步回调等。

在爬虫程序中,我们需要从多个网页中获取数据,并根据数据的关联性进行处理。如果我们使用多线程或多进程来执行这些任务,容易在处理数据关系上出现问题。使用生成器来执行任务,可以避免这个问题。

在异步回调中,我们需要同时执行多个异步任务,并且等待所有任务执行完成后,将返回值汇总。通过使用生成器和 yield from 语句来执行这些异步任务,可以大大提高代码的可读性和执行效率。

5. 总结

在本文中,我们介绍了生成器和 yield from 语法。生成器是 Python 中非常强大的功能之一,可以帮助我们简化代码结构,并提高代码执行效率。yield from 语法是 Python 3.3 引入的语法,可以简化使用生成器的复杂度,并提高代码的可读性。yield from 语法适用于需要同时执行多个子任务的场景,例如爬虫程序和异步回调。

后端开发标签