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 中的两个相关的概念,但是有一些区别:
-
定义:生成器是一种特殊的迭代器,它可以生成一系列的值,而迭代器是一个对象,它实现了 iter 和 next 方法,可以返回一个值的序列。
-
创建:生成器可以通过定义生成器函数,在函数内部使用 yield 语句生成值;迭代器可以通过定义迭代器类,在类中实现 iter 和 next 方法。
-
效率:生成器函数在生成值时只需要暂停函数的执行,因此它具有更高的效率;迭代器类需要维护一个对象状态,因此效率较低。
-
用途:生成器适用于生成大量的数据,因为它可以在生成数据时保存函数的状态,从而避免占用大量内存;迭代器适用于处理少量数据,因为它需要创建一个对象维护状态。
因此,在实际开发中,我们可以根据数据量和处理效率的需求来选择使用生成器或迭代器。
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 异同
return
和 yield
都是用于在函数中终止执行的关键字,但是它们的作用是不同的。
-
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())
上面的代码中,task1
和 task2
是两个协程函数,它们可以在单独的任务中并行执行。main
函数是协程的入口,在这个函数中,我们创建了两个协程的对象 task1_coro
和 task2_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函数,…...

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…...

多行文本在块元素中垂直居中
单行文本垂直居中对齐 在块元素中,让单行文本居中,可以使用line-height等于块元素的高,即可让该单行文本垂直居中对齐。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><me…...
在 WebAssembly 中使用 C/C++ 和 libbpf 编写 eBPF 程序
作者:于桐,郑昱笙 eBPF(extended Berkeley Packet Filter)是一种高性能的内核虚拟机,可以运行在内核空间中,用来收集系统和网络信息。随着计算机技术的不断发展,eBPF 的功能日益强大,…...
leveldb源码解析六——compact
compact分为manual_compaction、minor_compaction、major_compaction,统一由MaybeScheduleCompaction触发: void DBImpl::MaybeScheduleCompaction() {mutex_.AssertHeld();if (background_compaction_scheduled_) {// Already scheduled} else if (shu…...

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

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

记一次上环境获取资源失败的案例
代码结构以及资源位置 测试代码 RestController RequestMapping("/json") public class JsonController {GetMapping("/user/1")public String queryUserInfo() throws Exception {// 如果使用全路径, 必须使用/开头String path JsonController.class.ge…...

实战超详细MySQL8离线安装
在RedHat中,RPM Bundle 方式安装MySQL8。建议一定要用 RPM Bndle 版本安装,包全。官网下载:https://dev.mysql.com/downloads/mysql/1.卸载mariadb,会与MySQL安装冲突。rpm -qa | grep mariadb 查看有无mariadb如果有࿰…...
依赖倒置原则|SOLID as a rock
文章目录 意图动机:违反依赖倒置原则解决方案:C++中依赖倒置原则的例子依赖倒置原则的优点1、可复用性2、可维护性在C++中用好DIP的标准总结本文是关于 SOLID as Rock 设计原则系列的五部分中的 最后一部分。 SOLID 设计原则侧重于开发 易于维护、可重用和可扩展的软件。 在…...

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

handler解析(2) -Handler源码解析
目录 基础了解: 相关概念解释 整体流程图: 源码解析 Looper 总结: sendMessage 总结: ThreadLocal 基础了解: Handler是一套 Android 消息传递机制,主要用于线程间通信。实际上handler其实就是主线程在起了一…...
【算法】kmp
KMP算法 名称由来 是由发明这个算法的三个科学家的名称首字母组成 作用 用于字符串的匹配问题 举例说明 字符串 aabaabaaf 模式串 aabaaf 传统匹配方法 第一步 aabaabaaf aabaaf 此时,b和f不一致,则把模式串从头和文本串的第二个字符开始比 第…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...