【Python】yield函数

news2025/1/19 16:17:32

【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 1
    yield 2
    yield 3

gen = simple_generator()
print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3
  • 使用 for 循环遍历生成器
    生成器对象是可迭代的,因此可以使用 for 循环来遍历生成器生成的值。
    下面例子中,for 循环遍历生成器函数生成的所有值,并依次打印它们。
def simple_generator():
    yield 1
    yield 2
    yield 3

for 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 1
    yield 2
    yield 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 = yield
        print(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 i

def generator_b():
    for i in range(3, 6):
        yield i

def combined_generators():
    # 使用 yield 直接产出每个生成器中的元素
    for value in generator_a():
        yield value
    for 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 i

def generator_b():
    for i in range(3, 6):
        yield i

def combined_generators():
    # 直接使用 yield 产出额外的值
    yield "Start"
    
    # 使用 yield from 委托给子生成器 a
    yield from generator_a()
    
    # 再次直接使用 yield 产出中间的值
    yield "Middle"
    
    # 使用 yield from 委托给子生成器 b
    yield 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 + value2
    except StopIteration:
        pass

def 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 line

for line in read_large_file('large_file.txt'):
    print(line, end='')

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

  • 实现协程和并发
    生成器可以用于实现协程和并发编程模式。
    协程是一种用户态的轻量级线程,可以用来模拟异步操作,实现非阻塞的I/O处理等。
def coroutine_example():
    while True:
        received = yield
        print(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 * 2

def pipeline_stage2(data):
    for item in data:
        yield item + 1

data = 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 + value2
    except StopIteration:
        pass

def 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的标准库中已经提供了多种并发模型,但生成器可以作为一种轻量级的协程实现,用于实现简单的并发任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2278981.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python实现pdf转word和excel

一、引言   在办公中,我们经常遇收到pdf文件格式,因为pdf格式文件不易修改,当我们需要编辑这些pdf文件时,经常需要开通会员或收费功能才能使用编辑功能。今天,我要和大家分享的,是如何使用python编程实现…

【实践】操作系统智能助手OS Copilot新功能测评

一、引言 数字化加速发展,尤其人工智能的发展速度越来越快。操作系统智能助手成为提升用户体验与操作效率的关键因素。OS Copilot借助语言模型,人工智能等,对操作系统的自然语言交互操作 推出很多功能,值得开发,尤其运…

人物一致性训练测评数据集

1.Pulid 训练:由1.5M张从互联网收集的高质量人类图像组成,图像标题由blip2自动生成。 测试:从互联网上收集了一个多样化的肖像测试集,该数据集涵盖了多种肤色、年龄和性别,共计120张图像,我们称之为DivID-120,作为补充资源,还使用了最近开源的测试集Unsplash-50,包含…

【深度学习实战】kaggle 自动驾驶的假场景分类

本次分享我在kaggle中参与竞赛的历程,这个版本是我的第一版,使用的是vgg。欢迎大家进行建议和交流。 概述 判断自动驾驶场景是真是假,训练神经网络或使用任何算法来分类驾驶场景的图像是真实的还是虚假的。 图像采用 RGB 格式并以 JPEG 格式…

网络编程 | UDP套接字通信及编程实现经验教程

1、UDP基础 传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议。在上一篇博客文章中,已经对TCP协议及如何编程实现进行了详细的梳理讲解,在本文中,主要讲解与TCP一样广泛使用了另一种协议&#xff1a…

【Linux】线程全解:概念、操作、互斥与同步机制、线程池实现

🎬 个人主页:谁在夜里看海. 📖 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长,行则将至 目录 📚一、线程概念 📖 回顾进程 📖 引入线程 📖 总结 &a…

掌握未来:从零开始学习生成式AI大模型!

随着人工智能技术的飞速发展,生成式AI大模型已成为当今科技领域的热点。从文本生成、图像创作到音乐创作,生成式AI大模型在各个领域展现出惊人的潜力。本文将带领大家从零开始,逐步学习生成式AI大模型,掌握未来的关键技术。 一、生…

多肽合成 -- 液相合成(liquid-phase peptide synthesis (LPPS))

液相合成的定义 液相合成(Solution Synthesis)是指在液体介质中进行的化学合成反应,是化学合成中一种基本且重要的方法。它涉及到将反应物溶解在溶剂中,在一定的温度、压力和其他反应条件下进行化学反应,从而生成所需的…

第23篇 基于ARM A9处理器用汇编语言实现中断<五>

Q:怎样修改HPS Timer 0定时器产生的中断周期? A:在上一期实验的基础上,可以修改按键中断服务程序,实现红色LED上的计数值递增的速率,主程序和其余代码文件不用修改。 实现以下功能:按下KEY0…

ChatGPT大模型极简应用开发-CH1-初识 GPT-4 和 ChatGPT

文章目录 1.1 LLM 概述1.1.1 语言模型和NLP基础1.1.2 Transformer及在LLM中的作用1.1.3 解密 GPT 模型的标记化和预测步骤 1.2 GPT 模型简史:从 GPT-1 到 GPT-41.2.1 GPT11.2.2 GPT21.2.3 GPT-31.2.4 从 GPT-3 到 InstructGPT1.2.5 GPT-3.5、Codex 和 ChatGPT1.2.6 …

2025春秋杯冬季赛 day1 crypto

文章目录 通往哈希的旅程小哈斯RSA1ez_rsa 通往哈希的旅程 根据提示推断是哈希函数,ai一下,推测大概率是一个sha1,让ai写一个爆破脚本即可 import hashlib# 给定目标 SHA-1 哈希值 target_hash "ca12fd8250972ec363a16593356abb1f3cf…

广播网络实验

1 实验内容 1、构建星性拓扑下的广播网络,实现hub各端口的数据广播,验证网络的连通性并测试网络效率 2、构建环形拓扑网络,验证该拓扑下结点广播会产生数据包环路 2 实验流程与结果分析 2.1 实验环境 ubuntu、mininet、xterm、wireshark、iperf 2.2 实验方案与结果分析…

RustDesk ID更新脚本

RustDesk ID更新脚本 此PowerShell脚本自动更新RustDesk ID和密码,并将信息安全地存储在Bitwarden中。 特点 使用以下选项更新RustDesk ID: 使用系统主机名生成一个随机的9位数输入自定义值 为RustDesk生成新的随机密码将RustDesk ID和密码安全地存储…

JavaEE之常见的锁策略

前面我们学习过线程不安全问题,我们通过给代码加锁来解决线程不安全问题,在生活中我们也知道有很多种类型的锁,同时在代码的世界当中,也对应着很多类型的锁,今天我们对锁一探究竟! 1. 常见的锁策略 注意: …

数字图像处理:实验二

任务一: 将不同像素(32、64和256)的原图像放大为像素大 小为1024*1024的图像(图像自选) 要求:1)输出一幅图,该图包含六幅子图,第一排是原图,第 二排是对应放大…

WEB渗透技术研究与安全防御

目录 作品简介I IntroductionII 1 网络面临的主要威胁1 1.1 技术安全1 2 分析Web渗透技术2 2.1 Web渗透技术的概念2 2.2 Web漏洞产生的原因2 2.3 注入测试3 2.3.1 注入测试的攻击流程3 2.3.2 进行一次完整的Sql注入测试4 2.3.3 Cookie注入攻击11 3 安全防御方案设计…

使用 Thermal Desktop 进行航天器热分析

介绍 将航天器保持在运行温度下的轨道上是一个具有挑战性的问题。航天器需要处理太空非常寒冷的背景温度,同时还要管理来自内部组件、地球反照率和太阳辐射的高热负荷。航天器在轨道上可以进行的各种轨道机动使解决这个问题变得更加复杂。 Thermal Desktop 是一款…

乘联会:1月汽车零售预计175万辆 环比暴跌33.6%

快科技1月18日消息,据乘联会的初步推算,2025年1月狭义乘用车零售总市场规模预计将达到约175万辆左右。与去年同期相比,这一数据呈现了-14.6%的同比下降态势;而相较于上个月,则出现了-33.6%的环比暴跌情况。 为了更清晰…

SQL 递归 ---- WITH RECURSIVE 的用法

SQL 递归 ---- WITH RECURSIVE 的用法 开发中遇到了一个需求,传递一个父类id,获取父类的信息,同时获取其所有子类的信息。 首先想到的是通过程序中去递归查,但这种方法着实孬了一点,于是想,sql能不能递归查…

【机器学习实战入门项目】使用深度学习创建您自己的表情符号

深度学习项目入门——让你更接近数据科学的梦想 表情符号或头像是表示非语言暗示的方式。这些暗示已成为在线聊天、产品评论、品牌情感等的重要组成部分。这也促使数据科学领域越来越多的研究致力于表情驱动的故事讲述。 随着计算机视觉和深度学习的进步,现在可以…