首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python 高级编程之生成器与协程进阶(五)

一、概述

生成器是一种在 Python 中的迭代器生成器。生成器是一个函数,它生成一个迭代器。当生成器函数被调用时,它不会立即执行,而是返回一个生成器对象,该对象可以被用于迭代。生成器可以利用 yield 语句在函数内部生成值,并在函数调用者处接收这些值。

协程是一种高效的、内存友好的、线程内的并发技术,它可以让您在单个线程内并发地执行多个任务。协程是通过使用 async 关键字实现的,并可以在 Python 中的  库中使用。与线程不同,协程不需要额外的系统线程,因此它们比线程更高效、更灵活。

在简单的说法,生成器用于生成一系列的值,而协程用于在单个线程中并发执行多个任务。

二、生成器

生成器表达式本质上就是一个迭代器,是定义迭代器的一种方式,是允许自定义逻辑的迭代器。生成器使用表示。

生成器可以使用 for 循环或 next() 函数来遍历。当生成器对象被创建时,它会保存函数的当前状态,并在每次调用 next() 或 for 循环时从当前状态开始执行,直到遇到 yield 语句为止。

生成器遇到  语句时,它会生成当前的值,并保存函数的当前状态,以便下次调用时可以从该状态开始继续执行。当生成器再次被调用时,它会继续执行从上次暂停的地方开始,直到遇到下一个  或者  语句,或者函数结束为止。

下面是一个生成器函数的示例:

输出:

从上面的示例可以看出,生成器的工作原理是通过保存函数的当前状态,以便每次调用时从当前状态开始继续执行,并使用  语句生成值的。

1)生成器和迭代器的区别

生成器和迭代器是 Python 中的两个相关的概念,但是有一些区别:

定义生成器是一种特殊的迭代器,它可以生成一系列的值,而迭代器是一个对象,它实现了iternext方法,可以返回一个值的序列。

创建:生成器可以通过定义生成器函数,在函数内部使用 yield 语句生成值;迭代器可以通过定义迭代器类,在类中实现iternext方法。

效率:生成器函数在生成值时只需要暂停函数的执行,因此它具有更高的效率;迭代器类需要维护一个对象状态,因此效率较低。

用途:生成器适用于生成大量的数据,因为它可以在生成数据时保存函数的状态,从而避免占用大量内存;迭代器适用于处理少量数据,因为它需要创建一个对象维护状态。

因此,在实际开发中,我们可以根据数据量和处理效率的需求来选择使用生成器或迭代器。

2)生成器创建方式

在 Python 中,可以通过以下两种方式创建生成器:

1、通过生成器函数创建

通过在函数中使用 yield 语句,可以将函数变为生成器函数,每次调用生成器函数时,可以生成一个生成器。

例如:

2、通过生成器表达式创建

生成器表达式是一种简写的生成器创建方式,它基于列表推导式的语法。

例如:

以上是生成器的两种创建方式,您可以根据实际需求选择使用。

3)生成器表达式

生成器表达式是一种简写的生成器创建方式,它基于列表推导式的语法。

例如:

在上面的例子中,我们使用生成器表达式创建了一个生成器,该生成器生成从 0 到 2 的整数。然后,我们使用  函数逐个迭代生成器中的值。

4)yield关键字

关键字是 Python 中的一个关键字,用于生成器函数中。它允许一个函数在生成值时暂停其执行,以便在稍后恢复其执行并生成下一个值。这使生成器函数成为一种特殊的函数,可以按需生成一系列值。

5)生成器函数

生成器函数是 Python 中特殊的函数,该函数可生成一个生成器。与普通函数不同,生成器函数可以在每次被调用时生成一个生成器,并在生成器中生成一系列值。

生成器函数通过使用  语句创建生成器。每当函数执行到  语句时,生成器函数的执行就会暂停,并返回 yield 语句后面的值。当再次调用生成器函数时,它将从上次暂停的位置继续执行,直到遇到下一个  语句,或者函数返回。

例如:

在上面的例子中,我们定义了一个生成器函数 ,该函数通过使用  语句生成了三个整数:1、2 和 3。然后,我们通过调用该函数并将其结果分配给生成器 gen 来创建生成器,并使用  函数逐个迭代生成器中的值。

6)return 和 yield 异同

和  都是用于在函数中终止执行的关键字,但是它们的作用是不同的。

:当函数调用 return 时,函数立即终止执行,并返回一个值(如果存在)给调用者。该值通常表示函数的最终结果。

:当生成器函数调用 yield 时,它仅暂停其执行并生成一个值,但不终止函数。在下一次调用该生成器时,它将恢复其执行,直到遇到下一个  或终止函数。

因此, 是生成器函数的一个关键字,可以使生成器生成一系列值,而  是一般函数的一个关键字,它返回一个值并终止函数

7)yield的使用方法

关键字用于生成器函数。在生成器函数中,我们可以使用 yield 关键字生成一系列值,而无需暂停整个函数。

例如,以下是使用  关键字的简单生成器函数的例子:

我们可以使用  循环或  函数迭代生成器中的值,如下所示:

【注意】生成器函数只能迭代一次,所以请确保在使用生成器函数时存储其返回值。

8)for与next

在使用生成器时,我们可以使用两种不同的方法来迭代生成器中的值:和  函数。

for 循环:通过使用 for 循环,我们可以在生成器中迭代所有值。例如:

next() 函数:通过使用 next() 函数,我们可以手动控制生成器的迭代。例如:

【注意】在生成器迭代完所有的值后,再使用  函数将导致抛出 StopIteration 异常。因此,在使用 next() 函数时,请确保捕获该异常。

9)send的使用

方法是生成器的一种方法,它允许我们在生成器函数内部向生成器发送数据。该方法允许生成器接收外部数据,并使用这些数据生成结果

在使用  方法时,我们需要在生成器函数中使用  表达式来接收数据,如下所示:

【注意】第一次使用 send() 方法之前,我们需要调用 next() 函数,以启动生成器函数。此外,使用 send() 方法将导致抛出 StopIteration 异常,因此请确保在使用该方法时进行异常处理。

三、协程进阶

协程(Coroutine)是一种编程技巧,用于在多任务环境中实现轻量级的任务切换。与线程不同,协程不需要创建新的系统级线程,并且消耗的资源也比线程更少。因此,协程可以比线程更高效地完成任务。在我上篇的文章已经讲解了:IO模型和协程介绍

1)生成器与协程关系

生成器和协程是相关但有所不同的概念。生成器是一种特殊的迭代器,可以生成一系列的值,每次迭代时只返回一个值。生成器可以使用 yield 关键字来暂停执行,并在下一次调用时继续执行。

协程是一种并发编程技术,可以在单一线程中实现多个任务的并行执行。与线程不同,协程不需要创建新的系统级线程,并且消耗的资源也比线程更少。协程可以使用  关键字来暂停执行,并在下一次调用时继续执行。

因此,生成器可以用于实现协程,但它们不是协程的必需条件。在 Python 中,可以使用  库来实现协程,该库不需要使用生成器。不过,在实现协程时,生成器确实可以作为一种有效的工具,帮助开发者实现协程的暂停和恢复。

2)协程实现原理

协程的实现主要是通过一种叫做 "协程调度器" 的技术实现的,这种技术能够在不创建新的线程的情况下,在单一线程中按需切换协程的执行。协程调度器会管理当前正在运行的协程以及等待执行的协程,并在每个协程执行完后切换到下一个协程。

3)协程实现方式

在 Python 中,可以使用  库来实现协程。协程函数可以使用  关键字标记,表示该函数是一个协程函数。在协程函数中,可以使用  关键字等待其他协程完成,从而实现协程的切换。

在 Python 中,可以使用  库来实现协程。下面是一个简单的例子:

上面的代码中, 和  是两个协程函数,它们可以在单独的任务中并行执行。 函数是协程的入口,在这个函数中,我们创建了两个协程的对象  和 ,并通过  函数将它们并行执行。最后,我们通过  函数启动了整个协程。

运行上面的代码,可以得到以下输出:

可以看到,协程中的任务是并行执行的,因此我们可以充分利用 CPU 的资源,提高程序的执行效率。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20230429A0011400?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券