当前位置: 首页 > 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;则把模式串从头和文本串的第二个字符开始比 第…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#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"…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

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进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

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