当前位置: 首页 > news >正文

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

文章目录

    • 一、概述
    • 二、生成器
      • 1)生成器和迭代器的区别
      • 2)生成器创建方式
        • 1、通过生成器函数创建
        • 2、通过生成器表达式创建
      • 3)生成器表达式
      • 4)yield关键字
      • 5)生成器函数
      • 6)return 和 yield 异同
      • 7)yield的使用方法
      • 8)for与next
      • 9)send的使用
    • 三、协程进阶
      • 1)生成器与协程关系
      • 2)协程实现原理
      • 3)协程实现方式

一、概述

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

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

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

在这里插入图片描述

二、生成器

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

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

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

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

def my_generator():for i in range(3):yield igen = my_generator()
for i in gen:print(i)

输出:

0
1
2

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

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

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

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

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

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

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

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

2)生成器创建方式

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

1、通过生成器函数创建

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

例如:

def generator_example():yield 1yield 2yield 3gen = generator_example()
print(next(gen))
print(next(gen))
print(next(gen))

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

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

例如:

gen = (x for x in range(3))
print(next(gen))
print(next(gen))
print(next(gen))

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

3)生成器表达式

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

例如:

gen = (x for x in range(3))
print(next(gen))
print(next(gen))
print(next(gen))

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

4)yield关键字

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

5)生成器函数

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

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

例如:

def generator_example():yield 1yield 2yield 3gen = generator_example()
print(next(gen))
print(next(gen))
print(next(gen))

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

6)return 和 yield 异同

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

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

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

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

7)yield的使用方法

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

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

def simple_generator():yield 1yield 2yield 3yield 4yield 5gen = simple_generator()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
print(next(gen)) # Output: 4
print(next(gen)) # Output: 5

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

for value in simple_generator():print(value)# Output:
# 1
# 2
# 3
# 4
# 5

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

8)for与next

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

  • for 循环:通过使用 for 循环,我们可以在生成器中迭代所有值。例如:
def simple_generator():yield 1yield 2yield 3for value in simple_generator():print(value)# Output:
# 1
# 2
# 3
  • next() 函数:通过使用 next() 函数,我们可以手动控制生成器的迭代。例如:
def simple_generator():yield 1yield 2yield 3gen = simple_generator()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3

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

9)send的使用

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

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

def simple_generator():result = yieldprint("Received data:", result)gen = simple_generator()
next(gen)
gen.send("Hello, World!")
# Output: Received data: Hello, World!

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

三、协程进阶

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

1)生成器与协程关系

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

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

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

2)协程实现原理

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

3)协程实现方式

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

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

import asyncioasync def task1():print("Task 1 is running")await asyncio.sleep(1)print("Task 1 is complete")async def task2():print("Task 2 is running")await asyncio.sleep(1)print("Task 2 is complete")async def main():task1_coro = task1()task2_coro = task2()await asyncio.gather(task1_coro, task2_coro)if __name__ == "__main__":asyncio.run(main())

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

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

Task 1 is running
Task 2 is running
Task 1 is complete
Task 2 is complete

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


Python 高级编程之生成器与协程进阶讲解就先到这里了,有任何疑问欢迎给我留言,后续会持续更新相关技术文章,请小伙伴耐心等待,也可以关注我的公众号【大数据与云原生技术分享】进行深入技术交流~

相关文章:

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

文章目录一、概述二、生成器1)生成器和迭代器的区别2)生成器创建方式1、通过生成器函数创建2、通过生成器表达式创建3)生成器表达式4)yield关键字5)生成器函数6)return 和 yield 异同7)yield的使…...

Django框架之视图和URL

视图和URL 站点管理页面做好了, 接下来就要做公共访问的页面了.对于Django的设计框架MVT. 用户在URL中请求的是视图.视图接收请求后进行处理.并将处理的结果返回给请求者.使用视图时需要进行两步操作 1.定义视图2.配置URLconf 1. 定义视图 视图就是一个Python函数&#xff0c…...

Python 的Tkinter包系列之七:好例子补充2

Python 的Tkinter包系列之七:好例子补充2 英汉字典(使用文本文件记录英语单词和解释)、简单的通信录(使用SQLite数据库记录人员信息) 一、tkinter编写英汉字典 先看效果图: 词典文件是一个文本文件&…...

每日一练-等差数列

等差数列🍀题目描述🌿解题思路🌸Python源码📧Summary📆Date: 2023年2月10日 🎬Author: 小 y 同 学 📃Classify: 蓝桥杯每日一练 🔖Language: Python 🍀题目描述 题意   …...

使用动态参数构建CUDA图

文章目录使用动态参数构建CUDA图使用显式 API 调用构建 CUDA 图使用流捕获构建 CUDA 图组合方法执行结果总结使用动态参数构建CUDA图 自从在 CUDA 10 以来,CUDA Graphs 已被用于各种应用程序。 上图将一组 CUDA 内核和其他 CUDA 操作组合在一起,并使用指…...

在Fortran中调用Python教程

前言Python是机器学习领域不断增长的通用语言。拥有一些非常棒的工具包,比如scikit-learn,tensorflow和pytorch。气候模式通常是使用Fortran实现的。那么我们应该将基于Python的机器学习迁移到Fortran模型中吗?数据科学领域可能会利用HTTP AP…...

04-PS人像磨皮方法

1.高斯模糊磨皮 这种方法的原理就是建立一个将原图高斯模糊后图层, 然后用蒙版加画笔或者历史画笔工具将需要磨皮的地方涂抹出来, 通过图层透明度, 画笔流量等参数来控制磨皮程度 1.新建图层(命名为了高斯模糊磨皮), 混合模式设置为正常, 然后选择高斯模糊, 模糊数值设置到看…...

nginx反向代理+负载均衡上传webshell重难点+apache漏洞

nginx反向代理 nginx 负载均衡 负载均衡的策略 1、轮询:nginx默认就是轮询其权重都默认为1,服务器处理请求的顺序:ABABABABAB… upstream mysvr { server 192.168.137.131; server 192.168.137.136; }2、weight:跟据配置…...

transition组件的使用

<template><button click"flag !flag">切换</button><transition name"fade"><div v-if"flag" class"box"></div></transition> </template><script setup lang"ts"&g…...

多行文本在块元素中垂直居中

单行文本垂直居中对齐 在块元素中&#xff0c;让单行文本居中&#xff0c;可以使用line-height等于块元素的高&#xff0c;即可让该单行文本垂直居中对齐。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><me…...

在 WebAssembly 中使用 C/C++ 和 libbpf 编写 eBPF 程序

作者&#xff1a;于桐&#xff0c;郑昱笙 eBPF&#xff08;extended Berkeley Packet Filter&#xff09;是一种高性能的内核虚拟机&#xff0c;可以运行在内核空间中&#xff0c;用来收集系统和网络信息。随着计算机技术的不断发展&#xff0c;eBPF 的功能日益强大&#xff0c…...

leveldb源码解析六——compact

compact分为manual_compaction、minor_compaction、major_compaction&#xff0c;统一由MaybeScheduleCompaction触发&#xff1a; void DBImpl::MaybeScheduleCompaction() {mutex_.AssertHeld();if (background_compaction_scheduled_) {// Already scheduled} else if (shu…...

数据结构(二):单向链表、双向链表

数据结构&#xff08;二&#xff09;一、什么是链表1.数组的缺点2.链表的优点3.链表的缺点4.链表和数组的区别二、封装单向链表1. append方法&#xff1a;向尾部插入节点2. toString方法&#xff1a;链表元素转字符串3. insert方法&#xff1a;在任意位置插入数据4.get获取某个…...

COCO物体检测评测方法简介

本文从ap计算到map计算&#xff0c;最后到coco[0.5:0.95:0.05] map的计算&#xff0c;一步一步拆解物体检测指标map的计算方式。 一、ap计算方法 一个数据集有多个类别&#xff0c;对于该数据库有5个gt&#xff0c;算法检测出来10个bbox&#xff0c;对于人这个类别来说检测有…...

记一次上环境获取资源失败的案例

代码结构以及资源位置 测试代码 RestController RequestMapping("/json") public class JsonController {GetMapping("/user/1")public String queryUserInfo() throws Exception {// 如果使用全路径, 必须使用/开头String path JsonController.class.ge…...

实战超详细MySQL8离线安装

在RedHat中&#xff0c;RPM Bundle 方式安装MySQL8。建议一定要用 RPM Bndle 版本安装&#xff0c;包全。官网下载&#xff1a;https://dev.mysql.com/downloads/mysql/1.卸载mariadb&#xff0c;会与MySQL安装冲突。rpm -qa | grep mariadb 查看有无mariadb如果有&#xff0…...

依赖倒置原则|SOLID as a rock

文章目录 意图动机:违反依赖倒置原则解决方案:C++中依赖倒置原则的例子依赖倒置原则的优点1、可复用性2、可维护性在C++中用好DIP的标准总结本文是关于 SOLID as Rock 设计原则系列的五部分中的 最后一部分。 SOLID 设计原则侧重于开发 易于维护、可重用和可扩展的软件。 在…...

Webpack的知识要点

在前端开发中&#xff0c;一般情况下都使用 npm 和 webpack。   npm是一个非常流行的包管理工具&#xff0c;帮助开发者管理项目中使用的依赖库和工具。它可以方便地为项目安装第三方库&#xff0c;并在项目开发过程中进行版本控制。   webpack是一个模块打包工具&#xff…...

handler解析(2) -Handler源码解析

目录 基础了解&#xff1a; 相关概念解释 整体流程图&#xff1a; 源码解析 Looper 总结&#xff1a; sendMessage 总结&#xff1a; ThreadLocal 基础了解&#xff1a; Handler是一套 Android 消息传递机制,主要用于线程间通信。实际上handler其实就是主线程在起了一…...

【算法】kmp

KMP算法 名称由来 是由发明这个算法的三个科学家的名称首字母组成 作用 用于字符串的匹配问题 举例说明 字符串 aabaabaaf 模式串 aabaaf 传统匹配方法 第一步 aabaabaaf aabaaf 此时&#xff0c;b和f不一致&#xff0c;则把模式串从头和文本串的第二个字符开始比 第…...

git 常用命令之 git checkout

大家好&#xff0c;我是 17。 git checkout 是 git 中最重要最常用的命令之一&#xff0c;本文为大家详细解说一下。 恢复工作区 checkout 的用途之一是恢复工作区。 git checkout . checkout . 表示恢复工作区的所有更改,未跟踪的文件不会有变化。 恢复工作区的所有文件风…...

一些常见错误

500状态码: 代表服务器业务代码出错, 也就是执行controller里面的某个方法的过程中报错, 此时在IDEA的控制台中会显示具体的错误信息, 所以需要去看IDEA控制台的报错404状态码: 找不到资源找不到静态资源 检查请求地址是否拼写错误 检查静态资源的位置是否正确 如果以上都没有问…...

[单片机框架][调试功能] 回溯案发现场

程序莫名死机跑飞&#xff0c;不知道问题&#xff0c;那么下面教你回溯错误源 回溯案发现场一、修改HardFault_Handler1. xx.s 在启动文件&#xff0c;找到HardFault_Handler。并修改。2. 定义HardFault_Handler_C函数。&#xff08;主要是打印信息并存储Flash&#xff09;3. 根…...

MySQL主从同步-(二)搭建从机服务器

在docker中创建并启动MySQL从服务器&#xff1a;**端口3307docker run -d \-p 3307:3306 \-v /atguigu/mysql/slave1/conf:/etc/mysql/conf.d \-v /atguigu/mysql/slave1/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD123456 \--name atguigu-mysql-slave1 \mysql:8.0.3创建MyS…...

Linux系列 备份与分享文档

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.备份与分享文档 1.使用压缩和解压缩工具 &#xff08;1&…...

SNI生效条件 - 补充nginx-host绕过实例复现中SNI绕过的先决条件

文章目录1.前置环境搭建2.测试SNI生效条件(时间)3. 证书对SNI的影响3.1 双方使用同一个证书&#xff1a;3.2 双方使用不同的证书与私钥4. 端口号区分测试4.1 端口号区分&#xff0c;证书区分&#xff1a;4.2 端口号区分,证书不区分&#xff1a;5.总结SNI运行机制6. SNI机制绕过…...

傻白探索Chiplet,Modular Routing Design for Chiplet-based Systems(十一)

阅读了Modular Routing Design for Chiplet-based Systems这篇论文&#xff0c;是关于多chiplet通信的&#xff0c;个人感觉核心贡献在于实现了 deadlock-freedom in multi-chiplet system&#xff0c;而不仅仅是考虑单个intra-chiplet的局部NoC可以通信&#xff0c;具体的一些…...

C语言静态库、动态库的封装和注意事项

1、动态库、静态库介绍 参考博客&#xff1a;《静态库和动态库介绍以及Makefile》&#xff1b; 2、代码目录结构和编译脚本 参考博客&#xff1a;《实际工作开发中C语言工程的目录结构分析》&#xff1b; 3、编写库的流程 (1)明确需求:需求是否合理、需求的使用场景、需求可能遇…...

MyBatis-Plus分页插件和MyBatisX插件

MyBatis-Plus分页插件和MyBatisX插件六、插件1、分页插件a>添加配置类b>测试八、代码生成器1、引入依赖2、快速生成十、MyBatisX插件1、新建spring boot工程a>引入依赖b>配置application.ymlc>连接MySQL数据库d>MybatisX逆向生成2、MyBatisX快速生成CRUD申明…...

年前无情被裁,面试大厂的这几个月…

2月份了&#xff0c;金三银四也即将来临&#xff0c;在这个招聘季&#xff0c;大厂也开始招人&#xff0c;但还是有很多人吐槽说投了很多简历&#xff0c;却迟迟没有回复… 另一面企业招人真的变得容易了吗&#xff1f;有企业HR吐槽&#xff0c;简历确实比以前多了好几倍&…...

动态网站开发的前景/百度霸屏推广靠谱吗

报告类型&#xff1a;产业研究报告格式&#xff1a;电子版、纸介版、电子纸介出品单位&#xff1a;智研咨询官网链接&#xff1a;中国产业信息网 - 产业前景投资趋势门户-智研旗下产业信息咨询平台​www.chyxx.com报告链接&#xff1a;2021-2027年中国载货电梯行业市场调查研究…...

解读wordpress php代码/罗湖区seo排名

当我们的QQ在异地登录的时候会有消息提醒&#xff0c;对于安全性要求比较高的web网站&#xff0c;特别是后台管理&#xff0c;有时候需要甄别自己的账号是否被盗或者是否有另一个人此刻登陆了在进行后台操作&#xff0c;这些都会很不安全&#xff0c;为了避免两个人同时登录同时…...

郑州网站建设案例/网络营销方法有哪些?

《被讨厌的勇气》&#xff0c;作者岸见一郎 古贺史健&#xff0c;豆瓣链接&#xff1a;https://book.douban.com/subject/26369699/ 主旨&#xff1a;以对话形式阐述阿德勒心理学。阿德勒心理学有许多反常识的方面&#xff0c;如&#xff1a;否定原因论、采取目的论、人的烦恼全…...

做购物商城网站建设/百度手机应用市场

来源&#xff1a;雪球App&#xff0c;作者&#xff1a; 私募之家THS&#xff0c;&#xff08;https://xueqiu.com/5808549553/129022113&#xff09; 导读&#xff1a;同花顺智能交易终端MindGo版已上线2年多&#xff0c;凭借着同花顺深厚的技术底蕴&#xff0c;不断地对终端进…...

局域网网站域名怎么做/石家庄网站优化

在前面两篇介绍了Socket框架的设计思路以及数据传输方面的内容&#xff0c;整个框架的设计指导原则就是易于使用及安全性较好&#xff0c;可以用来从客户端到服务端的数据安全传输&#xff0c;那么实现这个目标就需要设计好消息的传输和数据加密的处理。本篇主要介绍如何利用So…...

wordpress添加上一篇下一页/成都门户网站建设

分割GBK中文遭遇乱码的解决方法类似如下的字符串(GBK), explode不能得到正确结果:1.$result explode("|", "滕华弢|海青"); 究其原因, 对于”弢”字(读tao,不认识没关系,我也不认识), 因为他的GBK编码值为: 8f7c, 不巧的是, “|”的ASCII值也是7c.这样的问…...