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 语法适用于需要同时执行多个子任务的场景,例如爬虫程序和异步回调。