【Python基础】生成器

news2024/10/7 8:26:29

文章目录

    • @[toc]
      • 什么是生成器
      • 生成器示例
      • 生成器工作流程
      • 生成器表达式
      • `send()`方法和`close`方法
        • `send()`方法
        • `close()`方法

什么是生成器

  • Python中,使用生成器可以很方便地支持迭代器协议
  • 生成器通过生成器函数产生,通过def定义,但不是通过return返回,而是通过yield一次返回一个结果,在每个结果之间挂起和继续它们的状态,来实现迭代器协议
  • yield本质上是一个语法糖,内部是一个状态机,维护着挂起和继续的状态,从而支持迭代器协议

生成器示例

def my_range(n):
    i = 0
    while i < n:
        yield i

        i += 1


my_range = my_range(3)

print(my_range)

print(next(my_range))
print(next(my_range))
print(next(my_range))
<generator object my_range at 0x0000019CE75804A0>
0
1
2
  • 在这个例子中,定义了一个生成器函数my_range()
  • 调用生成器函数会返回一个生成器对象,本质上是返回生成器对象的迭代器,通常直接称为生成器
  • 既然生成器本质上是一个迭代器,那么其内部需要实现__iter__()方法和__next__()方法,dir()函数可以获取一个对象的所有属性和方法,可以使用dir()函数查看生成器对象的属性和方法
def my_range(n):
    i = 0
    while i < n:
        yield i

        i += 1


my_range = my_range(3)

print(dir(my_range))

print('__iter__' in dir(my_range))
print('__next__' in dir(my_range))
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
True
True

生成器工作流程

  • 在上面的例子中加入一些打印信息,进一步看看生成器的工作流程
def my_range(n):
    print('开始迭代...')

    i = 0
    while i < n:
        print('迭代中...')

        yield i

        print('-' * 10)

        i += 1

        print('迭代结束')


gen_obj = my_range(3)

print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))
开始迭代...
迭代中...
0
----------
迭代结束
迭代中...
1
----------
迭代结束
迭代中...
2

1

  • 通过结果可以看到:
    • 当调用生成器函数的时候,函数只是返回了一个生成器对象,并没有运行
    • 当第一次调用next()方法的时候,生成器函数才开始运行,运行到yield语句处停止,并将i作为返回值返回,执行过程为图中的①
    • 当继续调用next()方法的时候,生成器函数从上一次停止的地方,也就是yield语句处继续运行,直到再次运行到yield语句处停止, 并将i作为返回值返回,执行过程为图中的②③
    • 如果下一次迭代不能运行到yield语句,就抛出StopIteration异常,生成器在当前yield语句处停止,不再执行②③过程

生成器表达式

  • 在介绍生成器表达式之前,先看看我们已经比较熟悉的列表解析
nums = [i for i in range(10) if i % 2]

print(nums)
[1, 3, 5, 7, 9]
  • 上述列表解析返回一个包含 1 1 1 10 10 10之间所有奇数的列表
  • 当序列很长,而每次只需要获取一个元素时,应当考虑生成器而不是列表解析
  • 生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的
gen_obj = (i for i in range(10) if i % 2)

print(gen_obj)
<generator object <genexpr> at 0x000001D6DC1E04A0>
  • 生成器表达式并不是返回一个列表,而是返回一个生成器
  • 使用生成器时,每迭代一次会产生(yield)出一个值来,实现了惰性加载(懒加载),只有在被迭代时才被赋值,并覆盖上一个值,所以在序列较长的情况下,使用生成器会优化内存

send()方法和close方法

  • 生成器中有两个重要的方法:send()方法和close方法
send()方法
  • Python 2.5中,yield语句变成了yield表达式,也就是说yield可以有一个值,而这个值就是send()方法的参数,通过调用send()方法将值传递给yield,而send()的返回值为yield返回的值,所以send(None)next()是等效的
  • 注意,调用send()传入非None值前,生成器必须处于挂起状态,否则将抛出异常,也就是说,第一次运行生成器时,只能使用next()send(None),因为没有yield来接收这个值
def my_range(n):
    i = 0
    while i < n:
        var = yield i

        print(f'var 的值为 {var}')

        i += 1


my_range = my_range(3)

print(my_range.send(None))
print(my_range.send('hello'))
print(my_range.send('world'))
0
var 的值为 hello
1
var 的值为 world
2
close()方法
  • close()方法用于关闭生成器,对关闭后的生成器再次调用next()send()将抛出StopIteration异常
def my_range(n):
    i = 0
    while i < n:
        var = yield i

        print(f'var 的值为 {var}')

        i += 1


my_range = my_range(3)

print(my_range.send(None))
print(my_range.send('hello'))

my_range.close()

print(my_range.send('world'))
0
var 的值为 hello
1
Traceback (most recent call last):
  File "C:/Users/FOLLOW_MY_HEART/Desktop/Python基础/【Python基础】迭代器/test.py", line 18, in <module>
    print(my_range.send('world'))
StopIteration

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

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

相关文章

酷雷曼再获“国家高新技术企业”认定

2023年12月8日&#xff0c;《对湖北省认定机构2023年认定报备的第五批高新技术企业拟进行备案的公示》正式发布&#xff0c;酷雷曼武汉同创蓝天科技有限公司成功获评“国家高新技术企业”认定。 屡获权威认定&#xff0c;见证硬核实力 被评定为高新技术企业是我国企业最高荣誉…

武汉小程序开发全攻略:从创意到上线,10个必备步骤详解

在当前数字化时代&#xff0c;小程序已经成为企业营销和服务的重要工具。特别是在武汉这样的创新型城市&#xff0c;小程序开发更是备受青睐。本文将为您详细解读武汉小程序开发的全攻略&#xff0c;从创意到上线的10个必备步骤。 步骤一&#xff1a;确定小程序类型和功能定位…

DSP捕获输入简单笔记

之前使用stm32的大概原理是&#xff1a; 输入引脚输入一个脉冲&#xff0c;捕获1开始极性捕获&#xff0c;捕获的是从启动捕获功能开始计数&#xff0c;捕获的是当前的计数值&#xff1b; 例如一个脉冲&#xff0c;捕获1捕获上升沿&#xff0c;捕获2捕获下降沿&#xff1b;而两…

mysql自动安装脚本(快速部署mysql)

mysql_install - 适用于生产环境单实例快速部署 MySQL8.0 自动安装脚本 mysql8_install.sh&#xff08;执行前修改一下脚本里的配置参数&#xff0c;改成你自己的&#xff09;&#xff08;博客末尾&#xff09; my_test.cnf&#xff08;博客末尾&#xff09;&#xff08;这个…

Linux性能优化常做的一些事情

Linux性能优化是一个广泛的主题&#xff0c;涉及多个方面。以下是一些常见的Linux性能优化建议&#xff1a; 硬件和系统配置&#xff1a; 使用SSD替代HDD。确保系统有足够的RAM。使用多核CPU。配置合适的网络硬件和带宽。 磁盘I/O性能&#xff1a; 使用RAID来提高I/O性能。使用…

WordCloud—— 词云

【说明】文章内容来自《机器学习入门——基于sklearn》&#xff0c;用于学习记录。若有争议联系删除。 wordcloud 是python的第三方库&#xff0c;称为词云&#xff0c;也成文字云&#xff0c;可以根据文本中的词频以直观和艺术化的形式展示文本中词语的重要性。 依赖于pillow …

物联网对接使用蓝牙还是WiFi,应该如何选择?

蓝牙是一种无线技术协议&#xff0c;可促进连接设备之间短距离的数据交换。它依赖于物理邻近性并使用2.400至2.485 GHz之间的UHF&#xff08;超高频&#xff09;无线电波。蓝牙旨在创建个人区域网络&#xff08;PAN&#xff09;并在笔记本电脑、智能手机和外围设备等计算设备之…

虚幻学习笔记18—C++委托(多播)和事件

一、前言 委托分单播和多播&#xff0c;多播就是可以绑定多个回调函数&#xff0c;然后一次性执行。这样也可以理解为啥多播没有返回值&#xff0c;多个回调函数执行后返回哪一个都是问题啊。而事件呢官方官方文档说法是“对于事件而言&#xff0c;只有定义事件的类才能调用 Br…

055:vue工具 --- 人民币小写转化为大写

第055个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

2023年国赛高教杯数学建模D题圈养湖羊的空间利用率解题全过程文档及程序

2023年国赛高教杯数学建模 D题 圈养湖羊的空间利用率 原题再现 规模化的圈养养殖场通常根据牲畜的性别和生长阶段分群饲养&#xff0c;适应不同种类、不同阶段的牲畜对空间的不同要求&#xff0c;以保障牲畜安全和健康&#xff1b;与此同时&#xff0c;也要尽量减少空间闲置所…

读取小数部分

1.题目描述 2.题目分析 //假设字符串为 char arr[] "123.4500"; 1. 找到小数点位置和末尾位置 代码如下&#xff1a; char* start strchr(arr, .);//找到小数点位置char* end start strlen(start) - 1;//找到末尾位置 如果有不知道strchr()用法的同学&#xf…

Html+单页面引入element以及Vue框架引用地址报错(unpkg.com国内无法访问可代替方案)

问题 单页面引入element以及vue 地址报错&#xff0c;请求超时 使用的引用地址是官网上提供&#xff0c;但是没解决问题 一、原因&#xff1a; unpkg也没有幸免于难&#xff0c;也被墙了&#xff0c;unpkg上的相关资源都不能访问&#xff0c;才导致项目资源加载不出。 二、…

linux gdb反汇编定位问题

日前解决一现网问题遇到补丁加载未生效现象&#xff0c;想要验证流程是否走进补丁代码&#xff0c;由于补丁函数和原函数名称一样&#xff0c;且修改代码较少&#xff0c;通过普通gdb方法难以看出是否走进补丁&#xff0c;但可用gdb反汇编方法来验证。 gdb该进程&#xff0c;之…

cdr格式怎么打开?cdr文件查看工具CDR Viewer功能介绍

CDRViewer Pro for Mac是一款专业的矢量图形文件查看器&#xff0c;主要用于打开、浏览和查看CorelDRAW&#xff08;CDR&#xff09;文件。以下是该软件的主要功能和特点&#xff1a; CDR文件支持&#xff1a;CDRViewer Pro可以快速加载和显示CorelDRAW&#xff08;CDR&#x…

python之双链表

双链表简单讲解 双向链表&#xff08;doubly linked list&#xff09;是一种链式数据结构&#xff0c;它的每个节点包含两个指针&#xff0c;一个指向前一个节点&#xff0c;一个指向后一个节点。与单向链表相比&#xff0c;双向链表可以在任何位置进行插入和删除操作&#xf…

MDC硬件笔记

学习资源来自华为 MDC210 80pin低速信号接口 4832pin 低速连接器的可插拔次数≤20 MiniFakra 视频接口 MiniFakra 视频连接器的可插拔次数≤ 25 次。 车载以太接口 1、2是100兆&#xff0c;3、4是1000兆 MTB300转接盒 前后面板接口总览&#xff1a; 1 低速接口1 40个…

如何使用Promethues监控系统指标并进行告警

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享。 前言 从零开始&#xff1a;使用Prometheus与Grafana搭建监控系统 克服网络障碍&#xff1a;Prometheus如何通过间接方式采集目标服务数据 在以上二节&#xff0c;我们介绍了如何使…

若依 ruoyi-vue3 集成aj-captcha实现滑块、文字点选验证码

目录 0. 前言0.1 说明 1. 后端部分1.1 添加依赖1.2. 修改 application.yml1.3. 新增 CaptchaRedisService 类1.4. 添加必须文件1.5. 移除不需要的类1.6. 修改登录方法1.7. 新增验证码开关获取接口1.8. 允许匿名访问 2. 前端部分&#xff08;Vue3&#xff09;2.1. 新增依赖 cryp…

re:Invent2023大会隆重推出自研芯片Graviton4和Trainium2

目录 一、前言 二、体验Graviton系列产品 &#xff08;一&#xff09;创建普通的EC2实例 &#xff08;二&#xff09;创建Graviton处理器的EC2实例 &#xff08;三&#xff09;远程到服务器 方式1&#xff1a;创建成功时连接 方式2&#xff1a;SSH客户端 方式3&#xff1a;正确…

airpods 无法使用Windows电脑充电的解决方法

打开设置 -> 蓝牙与其他设备 -> 显示更多设备 往下翻&#xff0c;找到“更多设备与打印机设置”&#xff0c;打开设备界面&#xff1a; 打开" Airpods Case"&#xff0c;找到“硬件”选项 -> 双击"符合HID标准的供应商定义设备" -> “驱动程序…