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

【Python】yield函数

【Python】yield函数

  • 1. yield介绍
  • 2.yield基本用法
  • 3.yield高级用法
    • 3.1 yield send() 方法
    • 3.2 yield from方法
    • 3.3 yield 和yield from叠加
    • 处理复杂情况下的叠加
  • 4.yield主要应用场景
  • 5.总结

python官方api地址

1. yield介绍

在Python中,yield关键字主要用于生成器函数(generator functions)中,其目的是使函数能够像迭代器一样工作,即可以被遍历,但不会一次性将所有结果都加载到内存中。

2.yield基本用法

  • 定义生成器函数
def simple_generator():yield 1yield 2yield 3gen = simple_generator()
print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3
  • 使用 for 循环遍历生成器
    生成器对象是可迭代的,因此可以使用 for 循环来遍历生成器生成的值。
    下面例子中,for 循环遍历生成器函数生成的所有值,并依次打印它们。
def simple_generator():yield 1yield 2yield 3for value in simple_generator():print(value)
  • 生成器表达式
    下面例子中,生成器表达式生成了一个平方数序列,并使用 for 循环打印所有值。
gen_expr = (x * x for x in range(5))
for value in gen_expr:print(value)
  • 生成器转列表
def simple_generator():yield 1yield 2yield 3
gen = simple_generator()
print(list(gen))  # 输出: [1, 2, 3]

3.yield高级用法

3.1 yield send() 方法

生成器不仅可以通过 yield 返回值,还可以通过 send() 方法接收外部输入。
send() 方法允许向生成器发送一个值,这个值将成为上一个 yield 表达式的值。
这种方式可以实现生成器与外部之间的双向通信。

def coroutine():while True:received = yieldprint(f"接收到的数据: {received}")co = coroutine()
next(co)  # 预激生成器
co.send(10)  # 输出: 接收到的数据: 10
co.send(20)  # 输出: 接收到的数据: 20

在这个例子中,coroutine 生成器函数在每次迭代时接收外部数据并打印它。
next(co) 用于预激生成器,使其准备好接收数据。

3.2 yield from方法

从Python 3.3开始,引入了 yield from 语法,它允许一个生成器委托另一个生成器来生成值。
这种委托机制可以简化嵌套生成器的使用,提高代码的可读性和效率。

def base_code_pool():for i in range(3):yield f'BASE-{i + 1}'def outsource_pool():for i in range(30):yield f'OUTS-{i + 1}'def team_member_code():yield from base_code_pool()print('内部资源编号用完,开始使用外包')yield from outsource_pool()team_member = team_member_code()
for i in range(5):print(next(team_member))

运行结果:

BASE-1
BASE-2
BASE-3
内部资源编号用完,开始使用外包
OUTS-1
OUTS-2

在这个例子中,team_member_code 生成器函数委托 base_code_pool outsource_pool 生成器来生成值。
base_code_pool 的值用完后,生成器会继续从 outsource_pool 生成值。

3.3 yield 和yield from叠加

yieldyield from 是 Python 中用于创建生成器的两种方式,它们允许函数在迭代过程中逐步返回值,而不是一次性返回所有结果。
这种特性使得生成器非常适合处理大型数据集或无穷序列等场景,因为它们不会一次性将所有数据加载到内存中,从而节省了内存资源。

关于是否可以“叠加”yield 和 yield from 的结果,实际上我们讨论的是如何组合多个生成器或者将一个生成器的结果传递给另一个生成器

  • 使用 yield 和 yield from 组合生成器
    当你想要组合两个或更多个生成器时,你可以使用 yield 来逐个产出每个生成器中的元素,或者使用 yield from 来直接委托给子生成器,让其负责产出自己的元素。
    例如:
def generator_a():for i in range(3):yield idef generator_b():for i in range(3, 6):yield idef combined_generators():# 使用 yield 直接产出每个生成器中的元素for value in generator_a():yield valuefor value in generator_b():yield value# 或者使用 yield from 委托给子生成器yield from generator_a()yield from generator_b()

在这个例子中,combined_generators 函数通过 yieldyield from 将两个生成器的结果进行了“叠加”。
这里,“叠加”的含义是指顺序地连接了两个生成器产生的输出流,而不是数学意义上的加法操作。
可以将 yieldyield from 结合使用来实现生成器之间的组合,甚至可以在同一个函数内部同时使用这两种语句。
这样做不仅可以简化代码结构,还能更灵活地控制生成器的行为。
让我们深入探讨一下如何有效地结合使用 yieldyield from 来“叠加”多个生成器的结果。

  • 结果的实际叠加
    如果我们谈论的是实际的结果叠加(如数值相加),那么你需要明确地编写逻辑来实现这一点。
    比如,如果你想把来自不同生成器的数值相加以获得总和,你可以这样做:
def sum_of_generators(gen1, gen2):return sum(gen1) + sum(gen2)total = sum_of_generators(generator_a(), generator_b())
print(total)  # 输出: 15 (0+1+2+3+4+5)
# 输出: 0 1 2 3 4 5
for item in combined_generators():print(item)

在这里,sum_of_generators 函数接收两个生成器作为参数,并分别对它们求和后再相加。
请注意,这种方法会立即消耗掉这两个生成器的所有元素并计算出总和,这可能不是最有效的做法,特别是对于非常大的数据集。

  • 组合使用 yield 和 yield from
    上面的例子可以将 yieldyield from 结合使用来实现生成器之间的组合,甚至可以在同一个函数内部同时使用这两种语句。
    这样做不仅可以简化代码结构,还能更灵活地控制生成器的行为。
    让我们深入探讨一下如何有效地结合使用 yieldyield from 来“叠加”多个生成器的结果。
    考虑一个场景,你有一个主生成器,它需要从多个子生成器中获取值,并且自身也可能产生一些额外的值。
    在这种情况下,你可以用 yield 来直接产出这些额外的值,而用 yield from 来委派给子生成器。
    例如:
def generator_a():for i in range(3):yield idef generator_b():for i in range(3, 6):yield idef combined_generators():# 直接使用 yield 产出额外的值yield "Start"# 使用 yield from 委托给子生成器 ayield from generator_a()# 再次直接使用 yield 产出中间的值yield "Middle"# 使用 yield from 委托给子生成器 byield from generator_b()# 最后直接使用 yield 产出结束的值yield "End"# 输出: Start 0 1 2 Middle 3 4 5 End
for item in combined_generators():print(item)

在这个例子中,combined_generators 函数展示了如何在同一个生成器内混合使用 yield yield from
首先,它通过 yield 发出了字符串 "Start"
然后,利用 yield from 将控制权交给 generator_a(),后者负责产出 0, 1, 和 2
接着,再次使用 yield 发出 "Middle";之后,又通过 yield fromgenerator_b() 产出 3, 4, 和 5
最后,以同样的方式发出字符串 "End"

这种方式允许你在不破坏原有逻辑的基础上轻松添加新的生成逻辑,同时也保持了代码的清晰度和可读性。

处理复杂情况下的叠加

如果你面对的是更加复杂的场景,比如你需要对来自不同生成器的数据进行某种形式的处理后再输出,或者你需要根据某些条件决定是否调用某个子生成器,那么你可以继续扩展这种模式。
例如,假设你想把两个生成器的结果相加后作为最终输出的一部分:

def add_generators(gen1, gen2):iterator1 = iter(gen1)iterator2 = iter(gen2)try:while True:value1 = next(iterator1)value2 = next(iterator2)yield value1 + value2except StopIteration:passdef enhanced_combined_generators():yield "Start"yield from add_generators(generator_a(), generator_b())yield "End"# 输出: Start 3 5 7 End
for item in enhanced_combined_generators():print(item)

综上所述,yieldyield from 的结果可以通过编程逻辑被“叠加”,但这取决于你想要实现的具体行为。
如果是简单的迭代输出,则可以直接使用 yield from 来简化代码;
而如果是数值或其他类型的累加,则需要额外的逻辑来完成这个过程。

4.yield主要应用场景

  • 处理大数据集
    生成器非常适合处理大数据集,因为它可以在需要时按需生成值,而不是一次性将所有值加载到内存中。
    这可以显著减少内存使用,提高程序的性能。
def read_large_file(file_path):with open(file_path, 'r') as file:for line in file:yield linefor line in read_large_file('large_file.txt'):print(line, end='')

在这个例子中,生成器函数 read_large_file 逐行读取大文件,并使用 for 循环打印每行内容。
这种方法避免了将整个文件加载到内存中,从而节省了内存。

  • 实现协程和并发
    生成器可以用于实现协程和并发编程模式。
    协程是一种用户态的轻量级线程,可以用来模拟异步操作,实现非阻塞的I/O处理等。
def coroutine_example():while True:received = yieldprint(f"处理数据: {received}")co = coroutine_example()
next(co)  # 预激生成器
co.send('data1')  # 输出: 处理数据: data1
co.send('data2')  # 输出: 处理数据: data2

在这个例子中, coroutine_example 生成器函数可以接收外部数据并处理它,实现了简单的协程功能。

  • 数据处理管道
    生成器可以用于实现数据处理管道,每个生成器函数负责一个处理步骤。
    这种模式可以将复杂的任务分解为多个简单的步骤,提高代码的可读性和可维护性。
def pipeline_stage1(data):for item in data:yield item * 2def pipeline_stage2(data):for item in data:yield item + 1data = range(5)
stage1 = pipeline_stage1(data)
stage2 = pipeline_stage2(stage1)for value in stage2:print(value)

在这个例子中,数据经过两个生成器函数处理。
首先在 pipeline_stage1 中乘以2,然后在 pipeline_stage2 中加1。

def add_generators(gen1, gen2):iterator1 = iter(gen1)iterator2 = iter(gen2)try:while True:value1 = next(iterator1)value2 = next(iterator2)yield value1 + value2except StopIteration:passdef enhanced_combined_generators():yield "Start"yield from add_generators(generator_a(), generator_b())yield "End"
# 输出: Start 3 5 7 End
for item in enhanced_combined_generators():print(item)这里定义了一个辅助函数 add_generators,它接受两个生成器并逐个取出它们的元素相加以生成新的值。enhanced_combined_generators 则是在之前的基础上加入了这个新功能。通过这种方式,你可以非常灵活地构建复杂的生成器逻辑,而不需要为每一个可能的变化都编写全新的生成器10

综上所述,yield 和 yield from 可以很好地协同工作,帮助开发者构建高效、易于维护的生成器代码。无论是简单的串联还是更复杂的操作,如数据变换或条件分支,都可以通过合理的设计达到预期的效果。重要的是要理解每种语句的作用以及它们如何相互作用,这样才能写出既强大又优雅的 Python 代码2。此外,yield from 的引入不仅简化了代码,还增强了生成器之间通信的能力,特别是在涉及到异常传递时显得尤为重要14。因此,在实际编程实践中,充分利用这两种工具能够极大地提升代码的质量和性能。

5.总结

  • yield函数属性
    • 当一个函数包含yield关键字时,这个函数就变成了一个生成器函数。
    • 调用生成器函数并不会立即执行函数体内的代码,而是返回一个生成器对象。
    • 生成器对象可以被迭代,每次迭代时,生成器函数会从上次离开的地方继续执行,直到遇到下一个yield语句,然后返回一个值,并保存当前状态,以便下次继续执行。
    • 这种行为使得生成器非常适合处理大量数据或流式数据,因为它不需要一次性将所有数据加载到内存中,从而节省了内存资源。
  • yield vs return
    • return:当函数执行到return语句时,它会立即停止执行,并返回一个值给调用。
      这意味着函数的局部变量会被销毁,且函数的执行状态不会被保存。
      因此,如果再次调用同一个函数,它将从头开始执行。
    • yield:与return不同,当执行到yield语句时,函数会暂停执行,返回一个值给调用者,并保存当前的所有局部变量状态。
      下次调用生成器时,函数将从上次暂停的地方恢复执行,直到遇到下一个yield语句或函数结束。
  • 生成器的使用场景
    • 处理大数据集:由于生成器是惰性求值的,它可以在需要时才生成数据,因此非常适合处理大数据集,避免了一次性加载所有数据导致的内存不足问题。
    • 简化代码结构:使用生成器可以简化代码结构,尤其是当需要处理复杂的状态机或递归结构时。
    • 协程与并发:虽然Python的标准库中已经提供了多种并发模型,但生成器可以作为一种轻量级的协程实现,用于实现简单的并发任务。

相关文章:

【Python】yield函数

【Python】yield函数 1. yield介绍2.yield基本用法3.yield高级用法3.1 yield send() 方法3.2 yield from方法3.3 yield 和yield from叠加处理复杂情况下的叠加 4.yield主要应用场景5.总结 python官方api地址 1. yield介绍 在Python中,yield关键字主要用于生成器函…...

Android13修改多媒体默认音量

干就完了! 设置音量为最大音量,修改如下: /framework/base/media/java/android/media/AudioSystem.java/** hide */public static int[] DEFAULT_STREAM_VOLUME new int[] {4, // STREAM_VOICE_CALL7, // STREAM_SYSTEM5, // STREAM_RING-5, // STREAM_MUSIC15, // STREAM…...

nginx+keepalived负载均衡及高可用

一、环境准备 主机名ip地址备注openEuler-1 192.168.121.11(本机) 192.168.131.11(心跳连接) nginx主负载均衡调度器openEuler-2 192.168.121.12(本机) 192.168.131.12(心跳连接) n…...

SP导入智能材质球

智能材质球路径 ...\Adobe Substance 3D Painter\resources\starter_assets\smart-materials 放入之后就会自动刷新...

Kotlin语言特性(一):空安全、扩展函数与协程

Kotlin语言特性(一):空安全、扩展函数与协程 一、引言 Kotlin作为Android官方推荐的开发语言,相比Java具有诸多现代化特性。本文将重点介绍Kotlin三个最具特色的语言特性:空安全、扩展函数和协程,并结合A…...

Sqlserver安全篇之_启用TLS即配置SQL Server 数据库引擎以加密连接

官方文档 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/configure-sql-server-encryption?viewsql-server-ver16 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/manage-certificates?viewsql-server-ver15&pre…...

Python 爬虫 – BeautifulSoup

Python 爬虫(Web Scraping)是指通过编写 Python 程序从互联网上自动提取信息的过程。 爬虫的基本流程通常包括发送 HTTP 请求获取网页内容、解析网页并提取数据,然后存储数据。 Python 的丰富生态使其成为开发爬虫的热门语言,特…...

【星云 Orbit-STM32F4】07. 用判断数据尾来接收据的串口通用程序框架

【星云 Orbit-STM32F4】用判断数据尾来接收一串数据的串口通用程序框架 摘要 本文介绍了一种基于STM32F407微控制器的串口数据接收通用程序框架。该框架通过判断数据尾来实现一串数据的完整接收,适用于需要可靠数据传输的应用场景。本文从零开始,详细讲…...

授权与认证之jwt(一)创建Jwt工具类

JWT的Token要经过加密才能返回给客户端&#xff0c;包括客户端上传的Tokn,后端项目需要验证核 实。于是我们需要一个WT工具类&#xff0c;用来加密Token和验证Token的有效性。 一、导入依赖 <dependency><groupId>com.auth0</groupId><artifactId>jav…...

Kubernetes Service服务发现dns之CoreDNS

文章目录 背景什么是Service、服务发现、Endpoint什么是CoreDNSCoreDNS 的工作原理 常用命令coredns 运行状态根据服务名&#xff0c;判断某个服务dns解析是否正常 背景 Kubernetes 集群内部的服务发现是微服务架构的核心基础&#xff0c;而 DNS 服务则是实现这一机制的关键组…...

Spring Boot 测试:单元、集成与契约测试全解析

一、Spring Boot 分层测试策略 Spring Boot 应用采用经典的分层架构&#xff0c;不同层级的功能模块对应不同的测试策略&#xff0c;以确保代码质量和系统稳定性。 Spring Boot 分层架构&#xff1a; Spring Boot分层架构 A[客户端] -->|HTTP 请求| B[Controller 层] …...

用友NC系列漏洞检测利用工具

声明&#xff01;本文章所有的工具分享仅仅只是供大家学习交流为主&#xff0c;切勿用于非法用途&#xff0c;如有任何触犯法律的行为&#xff0c;均与本人及团队无关&#xff01;&#xff01;&#xff01; 目录标题 YongYouNcTool启动及适配环境核心功能界面预览一键检测命令执…...

PostgreSQL 创建表格

PostgreSQL 创建表格 在数据库管理中&#xff0c;表格&#xff08;Table&#xff09;是数据存储的基础。PostgreSQL作为一款强大的开源对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;创建表格是其最基本的功能之一。本文将详细讲解如何在PostgreSQL中创…...

一周一个Unity小游戏2D反弹球游戏 - 球的死区及球重生

前言 本文将实现当球弹到球板下方的死亡区域后,球会被重置到球板上发射点,并且重置物理状态的逻辑。 创建球的死亡区 之前创建的在屏幕下方的空气墙碰撞体可以将其Is Trigger勾选上,让其成为一个触发器,用来检测球是否进入该区域,如下。 创建一个脚本名为Deadzone…...

本地部署 DeepSeek:从 Ollama 配置到 Spring Boot 集成

前言 随着人工智能技术的迅猛发展&#xff0c;越来越多的开发者希望在本地环境中部署和调用 AI 模型&#xff0c;以满足特定的业务需求。本文将详细介绍如何在本地环境中使用 Ollama 配置 DeepSeek 模型&#xff0c;并在 IntelliJ IDEA 中创建一个 Spring Boot 项目来调用该模型…...

vue3:三项目增加404页面

一、路由添加 1、官网地址 带参数的动态路由匹配 | Vue Routerhttps://router.vuejs.org/zh/guide/essentials/dynamic-matching.html 2、复制核心语句 { path: /:pathMatch(.*)*, name: NotFound, component: NotFound } 3、粘贴到路由index.js中 4、建立页面 在view文件夹…...

MCAL(Microcontroller Abstraction Layer)介绍

目录 MCAL的核心作用 MCAL的模块组成 1. 微控制器驱动&#xff08;Microcontroller Drivers&#xff09; 2. I/O驱动&#xff08;DIO, PWM, ADC等&#xff09; 3. 通信驱动&#xff08;Communication Drivers&#xff09; 4. 存储驱动&#xff08;Memory Drivers&#xf…...

爬虫:PhantomJS的详细使用和实战案例

文章目录 一、PhantomJS介绍1.1 什么是 PhantomJS1.2 PhantomJS 的特点与优势二、PhantomJS 的安装2.1 在 macOS 上安装 PhantomJS2.2 在 Linux 上安装 PhantomJS2.3 在 Windows 上安装 PhantomJS2.4 验证安装三、PhantomJS 的基本使用3.1 示例 1:打开网页并截图3.2 示例 2:获…...

目标检测——数据处理

1. Mosaic 数据增强 Mosaic 数据增强步骤: (1). 选择四个图像&#xff1a; 从数据集中随机选择四张图像。这四张图像是用来组合成一个新图像的基础。 (2) 确定拼接位置&#xff1a; 设计一个新的画布(输入size的2倍)&#xff0c;在指定范围内找出一个随机点&#xff08;如…...

深度学习工程师的技术图谱和学习路径

在构建一个深度学习工程师的技术图谱时,按照“技能树与能力模型”的结构可以帮助清晰地展示出技术体系的层次化关系,帮助学习者更好地理解每个技术点的依赖与顺序。 深度学习工程师的技术图谱和学习路径 以下是深度学习工程师的技能树,包括从基础到进阶的学习路径,以及对…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...