全网都在找的Python生成器竟然在这里!简单几步,让你的代码更简洁、更高效!

news2024/11/24 17:07:02

在这里插入图片描述

  • 博客主页:长风清留扬-CSDN博客
  • 系列专栏:Python基础专栏
  • 每天更新大数据相关方面的技术,分享自己的实战工作经验和学习总结,尽量帮助大家解决更多问题和学习更多新知识,欢迎评论区分享自己的看法
  • 感谢大家点赞👍收藏⭐评论

在这里插入图片描述

一、生成器的定义

生成器是一种特殊的迭代器,它允许你定义一个函数,该函数会按照你的要求生成一个序列的值,但一次只返回一个值,并且在内部维护着自己的状态,以便在需要时生成下一个值。生成器是通过使用yield关键字来实现的。
推荐阅读: 来看看Python迭代器能让你的代码提升100倍的密码

二、生成器的创建

生成器可以通过以下两种方式创建:

yield关键字

函数中包含yield关键字:当一个函数中包含至少一个yield语句时,该函数就不再是一个普通函数,而是一个生成器函数。调用该函数时,会返回一个生成器对象。
在Python中,yield关键字用于在函数中创建一个生成器。生成器是一种特殊的迭代器,它允许你逐个产生值,而不是一次性返回整个序列。使用yield关键字,你可以定义一个函数,该函数在每次调用时返回一个值,并保留其状态以供下次调用时继续执行。

语法

def generator_function_name(parameters):  
    """  
    这是一个生成器函数的定义。  
      
    :param parameters: 函数的参数,可以是任意数量和类型的参数。  
    :yield: 在函数体中,使用yield关键字来返回一个值,并暂停函数的执行。  
            每次迭代生成器时,函数会从上次yield的位置继续执行。  
    """  
    # 函数体:可以包含任意数量的语句和逻辑。  
    # 通常会有一个循环来逐个产生值。  
    for item in iterable:  # iterable是一个可迭代对象,比如列表、元组、集合或字符串等。  
        # 可以在这里进行任何需要的计算或处理。  
        yield value  # 使用yield返回一个值,并暂停函数的执行。  
        # 这里的代码(如果有的话)不会在每次迭代时都执行,  
        # 除非它位于另一个循环或条件语句中。  
    # 注意:生成器函数通常没有return语句(或者有一个不带值的return,表示迭代结束)。  
    # 如果有return语句并带有值,那么在迭代结束后尝试获取下一个值时,会引发StopIteration异常,  
    # 并且该值会被作为StopIteration异常的value属性返回(这是Python 3.3及以后版本的行为)。

示例1

def simple_generator():  
    """  
    一个简单的生成器函数,依次返回数字0到2。  
    """  
    yield 0  
    yield 1  
    yield 2  
  
# 使用生成器函数  
gen = simple_generator()  # 创建一个生成器对象  
  
# 迭代生成器对象  
for value in gen:  
    print(value)  # 输出:0, 1, 2

在上面的示例中,simple_generator是一个生成器函数,它使用yield关键字依次返回数字0、1和2。当我们调用这个函数时,它不会立即执行完并返回结果,而是返回一个生成器对象。然后,我们可以使用for循环或其他迭代方式来逐个获取生成器产生的值。

需要注意的是,生成器函数在每次迭代时都会从上次yield的位置继续执行,直到函数结束或再次遇到yield。这意味着你可以在生成器函数中保留状态(比如循环变量、内部变量等),并在下次迭代时继续使用它们。

示例2

def fibonacci(n):  
    """生成斐波那契数列的前n个数"""  
    a, b = 0, 1  
    for _ in range(n):  
        yield a  # 返回当前的斐波那契数  
        a, b = b, a + b  # 更新斐波那契数列的当前数和下一个数  
  
# 使用生成器函数  
fib_gen = fibonacci(5)  # 创建一个生成器对象  
for num in fib_gen:  # 迭代生成器对象  
    print(num)  # 打印每个斐波那契数

运行结果:

0  
1  
1  
2  
3

生成器表达式

  • 生成器表达式:生成器表达式类似于列表推导式,但使用圆括号而不是方括号。它们提供了一种简洁的方法来创建生成器。
  • 生成器表达式是另一种创建生成器的方式,它提供了一种简洁的语法来生成序列的值。生成器表达式使用圆括号()而不是方括号[]来定义,并且它们也使用yield关键字(尽管在表达式中这种用法是隐式的)。

语法

generator_expression = (expression for item in iterable [if condition])
  • expression:要生成的值的表达式。
  • item:从可迭代对象iterable中取出的元素。
  • iterable:要遍历的可迭代对象。
  • if condition(可选):一个条件表达式,用于过滤要生成的元素。

示例

# 创建一个生成器表达式,生成从0到9的平方数  
squares = (x**2 for x in range(10))  
  
# 使用for循环迭代生成器表达式  
for square in squares:  
    print(square)

运行结果:

0  
1  
4  
9  
16  
25  
36  
49  
64  
81

生成器表达式在语法上类似于列表推导式,但它们不会一次性生成整个列表,而是返回一个生成器对象,该对象在迭代时按需生成值。这使得生成器表达式在处理大数据集时更加高效,因为它们不会占用大量内存。

总之,生成器是Python中一个非常有用的特性,它们提供了一种惰性计算的方式,只在需要时才生成值,从而节省了内存和计算资源。通过生成器函数和生成器表达式,我们可以轻松地创建和使用生成器来处理迭代逻辑和大数据集。

三、访问生成器

使用for循环遍历生成器

首先,我们定义一个简单的生成器函数:

# 定义一个生成器函数,它逐个生成从0到4的数字  
def simple_generator():  
    for i in range(5):  
        yield i  # 使用yield关键字,使函数成为一个生成器  
  
# 使用for循环遍历生成器  
for value in simple_generator():  
    print(f"For loop value: {value}")

运行结果

For loop value: 0  
For loop value: 1  
For loop value: 2  
For loop value: 3  
For loop value: 4

使用__next__()方法访问生成器

生成器对象本身也有__next__()方法,可以实现与next()函数相同的功能:

# 重新创建生成器对象  
gen = simple_generator()  
  
# 使用生成器对象的__next__()方法获取下一个值  
print(f"__next__() value: {gen.__next__()}")  # 输出第一个值  
print(f"__next__() value: {gen.__next__()}")  # 输出第二个值  
print(f"__next__() value: {gen.__next__()}")  # 输出第三个值  
  
# 当生成器耗尽时,继续调用__next__()会引发StopIteration异常  
try:  
    print(f"__next__() value: {gen.__next__()}")  # 输出第四个值  
    print(f"__next__() value: {gen.__next__()}")  # 尝试获取第五个值,会抛出异常  
except StopIteration:  
    print("Generator exhausted")

输出结果:

__next__() value: 0  
__next__() value: 1  
__next__() value: 2  
__next__() value: 3  
Generator exhausted

使用next()方法访问生成器

我们可以直接使用next()函数来获取生成器的下一个值:

# 重新创建生成器对象  
gen = simple_generator()  
  
# 使用next()方法获取生成器的下一个值  
print(f"Next value: {next(gen)}")  # 输出第一个值  
print(f"Next value: {next(gen)}")  # 输出第二个值  
print(f"Next value: {next(gen)}")  # 输出第三个值  
  
# 当生成器耗尽时,继续调用next()会引发StopIteration异常  
try:  
    print(f"Next value: {next(gen)}")  # 输出第四个值  
    print(f"Next value: {next(gen)}")  # 尝试获取第五个值,会抛出异常  
except StopIteration:  
    print("Generator exhausted")

运行结果:

Next value: 0  
Next value: 1  
Next value: 2  
Next value: 3  
Generator exhausted

使用send()方法

send()方法不仅可以获取生成器的下一个值,还可以向生成器发送一个值(通过yield表达式接收)。需要注意的是,首次启动生成器不能使用send(),而必须使用next()或__next__()。

# 定义一个接受send值的生成器函数  
def generator_with_send():  
    received = yield "Start"  # 第一个yield,此时received是None  
    while True:  
        received = yield received  # 后续yield,将接收到的值发送回去  
  
# 创建生成器对象  
gen = generator_with_send()  
  
# 启动生成器  
print(f"First value: {next(gen)}")  # 必须首先使用next()启动  
  
# 使用send()发送值并获取生成器的下一个值  
print(f"Send value: {gen.send('First send value')}")  # 发送值并获取"First send value"  
print(f"Send value: {gen.send('Second send value')}")  # 再次发送值并获取"Second send value"  
  
# 为了避免无限循环,我们在这里停止  
# 在实际应用中,可以根据条件在生成器内部控制循环的结束

输出结果:

# 定义一个接受send值的生成器函数  
def generator_with_send():  
    received = yield "Start"  # 第一个yield,此时received是None  
    while True:  
        received = yield received  # 后续yield,将接收到的值发送回去  
  
# 创建生成器对象  
gen = generator_with_send()  
  
# 启动生成器  
print(f"First value: {next(gen)}")  # 必须首先使用next()启动  
  
# 使用send()发送值并获取生成器的下一个值  
print(f"Send value: {gen.send('First send value')}")  # 发送值并获取"First send value"  
print(f"Send value: {gen.send('Second send value')}")  # 再次发送值并获取"Second send value"  
  
# 为了避免无限循环,我们在这里停止  
# 在实际应用中,可以根据条件在生成器内部控制循环的结束

输出结果:

First value: Start  
Send value: First send value  
Send value: Second send value

四、yield关键字的作用

yield关键字在生成器函数中有以下几个作用:

  • 返回一个值给调用者:每次调用next()方法或迭代生成器对象时,生成器函数会从上次离开的位置继续执行,直到遇到下一个yield语句,并返回该语句的值。
  • 暂停函数执行:当生成器函数执行到yield语句时,它会暂停执行,并保存当前的所有局部变量和状态。下次调用next()方法时,它会从上次暂停的位置继续执行。
  • 记忆状态:生成器能够记住上一次迭代时的状态,这使得它能够在多次迭代中保持内部状态的一致性。

五、生成器的优势

生成器具有以下几个优势:

  • 惰性计算:生成器只在需要时才计算下一个值,这可以节省内存和计算资源。
  • 节省内存:由于生成器一次只返回一个值,并且使用迭代器协议进行迭代,因此它们可以处理大数据集而不会耗尽内存。
  • 简化代码:生成器提供了一种简洁的方法来编写迭代逻辑,使得代码更加清晰和易于维护。

六、生成器的应用场景

生成器适用于以下场景:

  • 处理大数据集:当数据集非常大时,使用生成器可以避免一次性将所有数据加载到内存中。
  • 需要惰性计算的场景:当只需要处理数据集的一部分时,生成器可以按需生成值,而无需计算整个数据集。
  • 自定义迭代逻辑:当需要自定义迭代逻辑时,生成器提供了一种灵活的方式来实现这一点。

推荐阅读

Python基础

Python全网最全基础课程笔记(一)——基础入门
Python全网最全基础课程笔记(二)——变量
Python全网最全基础课程笔记(三)——所有运算符+运算符优先级
Python全网最全基础课程笔记(四)——基本数据类型
Python全网最全基础课程笔记(五)——选择结构+Python新特性Match
Python全网最全基础课程笔记(六)——循环结构
Python全网最全基础课程笔记(七)——列表,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(八)——字典,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(九)——集合,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十)——元组,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十一)——字符串所有操作,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十二)——函数,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!
Python全网最全基础课程笔记(十三)——作用域,跟着思维导图和图文来学习,爆肝2w字,无数代码案例!

Flink入门到就业

2024年最新Flink教程,从基础到就业,大家一起学习–基础篇
2024年最新Flink教程,从基础到就业,大家一起学习–入门篇
2024年最新Flink教程,从基础到就业,大家一起学习–Flink集群部署
2024年最新Flink教程,从基础到就业,大家一起学习–flink部署和集群部署(从本地测试到公司生产环境如何部署项目源码)
2024年最新Flink教程,从基础到就业,大家一起学习–Flink运行架构底层源码详解+实战
2024年最新Flink教程,从基础到就业,大家一起学习–Flink DataStream API-第一篇+源码讲解

在这里插入图片描述

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

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

相关文章

【漏洞复现】网动统一通信平台/网动统一通信平台ActiveUC存在任意文件下载

》》》产品描述《《《 网动统一通信平台是采用统一的通信界面,将VoIP电话系统、电子邮件等多种沟通方式融合的企业IT平台。 》》》漏洞描述《《《 网动统一通信平台是采用统一的通信界面,将VoIP电话系统、电子邮件等多种沟通方式融合的企业IT平台。网动统…

OXO:一款针对Orchestration框架的安全扫描引擎

关于OXO OXO是一款针对Orchestration框架的安全扫描引擎,该工具可以帮助广大研究人员检测Orchestration安全问题,并执行网络侦查、 枚举和指纹识别等操作。 值得一提的是,OXO还提供了数十种其他的协同工具,包括网络扫描代理&…

js拼接html代码在线工具

具体请前往:在线Html转Js--将Html代码转成javascript动态拼接代码并保持原有格式

【基础篇】一个键值数据库包含什么?

背景 今天,在构造这个简单的键值数据库时,我们只需要关注整体架构和核心模块。这就相当于医学上在正式解剖人体之前,会先解剖一只小白鼠。我们通过剖析这个最简单的键值数据库,来迅速抓住学习和调优 Redis 的关键。 我们把这个简…

python中字符串操作

1、遍历字符串: pystr"HelloPython!" for i in pystr:print(i) 结果: 2、字符串索引 pystr"HelloPython!" print(pystr[0],pystr[-1]) 结果: 3、字符串切片 pystr"HelloPython!" # 切片[start:stop:step] p…

父组件向子组件传值props

父组件 <template><child :list"list" /><h4>{{ title }}</h4> </template> <script> // 引用子组件 import child from ./child.vue export default {data() {return {title: APP根组件,list: [a1, a2, a3]}},// 组件注册compo…

2024电动车新国标是什么标准

9月19日&#xff0c;工业和信息化部会同多部门&#xff0c;对最新修订的《电动自行车安全技术规范》进行公开征求意见&#xff0c;将持续1个月。与现行标准相比&#xff0c;这次的“新国标”做了哪些方面的改进和提升&#xff1f;事关你出行自由顺畅的“小电驴”&#xff0c;快…

【C语言】猜数字小游戏

&#x1f602;个人主页: 起名字真南 &#x1f923;个人专栏:【数据结构初阶】 【C语言】 【C】 目录 1 随机数的生成1.1 rand1.2 srand1.3 time1.4 设置随机数范围 2 猜数字游戏实现 前言&#xff1a;我们学习完前面的循环以后可以写一个猜数字小游戏 1 随机数的生成 想要完成…

假鞋检测分割系统源码&数据集分享

假鞋检测分割系统源码&#xff06;数据集分享 [yolov8-seg-C2f-DiverseBranchBlock&#xff06;yolov8-seg-C2f-SCConv等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAA…

C++11--默认成员函数控制 模板的可变参数

默认成员函数 之前学习C类中&#xff0c;有6个默认成员函数&#xff1a; 构造函数析构函数拷贝构造函数拷贝赋值重载取地址重载const 取地址重载 最重要的是前4个&#xff0c;默认成员函数就是我们不写编译器会生成一个默认的。在C11中新增了两个函数&#xff1a;移动构造函…

MySQL连接:内连接

先看我的表结构 dept表 emp表 内连接分为两个连接方式 1.隐式内连接 2.显式内连接 1.隐式内连接 基本语法 select 字段列表 FROM 表1, 表2 WHERE 条件... ;例子&#xff1a;查询每一个员工的姓名&#xff0c;及关联的部门的名称&#xff08;隐式内连接实现&#xff09; …

Pikachu-url重定向-不安全的url跳转

不安全的url跳转 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话就可能发生"跳错对象"的问题。 url跳转比较直接的危害是: …

LSTM模型变种

LSTM模型变种 一、GRU 1.什么是GRU GRU&#xff08;Gated Recurrent Unit&#xff09;是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;它被设计用来解决传统RNN在处理长序列时可能遇到的梯度消失或梯度爆炸问题。GRU通过引入门控机制来控制信息的流动&…

PCL 计算点云的高斯曲率

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 法向量计算 2.1.2 主曲率和高斯曲率计算 2.1.3 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&a…

1000万元试水,看完AI约稿平台上赚钱的故事,真的心动了……

在生成对抗网络&#xff08;GAN&#xff09;、扩散模型&#xff08;Diffusion Models&#xff09;、视觉语言预训练模型&#xff08;CLIP&#xff09;等技术的发展下&#xff0c;AI 绘画可做的内容越来越多。 建筑设计、服装设计、室内设计、插画设计等垂类模型的出现也让更多…

从理论到实践:AI智能分析网关V4烟火检测算法的应用场景探索

在信息化和智能化的今天&#xff0c;AI智能分析网关V4作为一款集成了先进技术的硬件设备&#xff0c;在烟火检测领域展现出了强大的应用价值。本文将详细阐述AI智能分析网关V4烟火检测算法的原理及其在各种场景中的应用。 一、AI智能分析网关V4烟火检测算法原理 深度学习基础…

激光测距用高精度时间测量(TDC)电路MS1003,比 MS1002 具有更高的精度和更小的封装,适合于高精度小封装的应用领域

MS1003 是一款高精度时间测量 (TDC) 电路&#xff0c;对比 MS1002 具 有更高的精度和更小的封装&#xff0c;适合于高精度小封装的应用领域。 MS1003 具有双通道、多脉冲的采样能力、高速 SPI 通讯、 多种测量模式&#xff0c;适合于激光雷达和激光测距。 主要特点 …

word 无法进入修订模式

word 无法进入修订模式&#xff0c;原来是被保护了&#xff0c;取消保护却没有密码 方法&#xff1a; 1、新建-空白文档 2、插入-对象-文件中的文字...&#xff0c;然后选择受保护的文档。这样即可把受保护的文档克隆一份到新文档。新文档当然就可以进入修订模式了。

Mac上最好用的快捷回复工具-快捷短语

网络上打字回复已经成为我们日常生活中不可缺少的一件事了&#xff0c;当有的时候需要一遍又一遍的回复重复的内容的时候&#xff0c;难免会感到疲惫&#xff0c;每次复制粘贴重复的内容&#xff0c;时间一长真的会很让人抓狂。 这里给大家推荐一款很好用的快捷回复工具&#…

全局变量的重复定义会怎样?

有些人的第一反应是编译不过吧&#xff1f; //fun.c void func() {printf("测试1"); }//main.c void func() {printf("测试2"); } void main() {func(); } 编译&#xff1a; 这里可以看到保存错了&#xff0c;因为func重复定义了。 但是重复定义就会全部…