迭代器和生成器的学习笔记
迭代器
Python 迭代器是一种对象,它实现了迭代协议,包括 __iter__() 和 __next__() 方法。迭代器可以让你在数据集中逐个访问元素,而无需关心数据结构的底层实现。与列表或其他集合相比,迭代器可以节省内存,因为它们一次只生成一个元素。
迭代器的基本特点
- 懒加载:迭代器不会一次性将所有数据加载到内存中,而是根据需要生成元素。
- 状态保持:迭代器在迭代过程中会保持其状态,可以从上次停止的地方继续迭代。
- 可以遍历:迭代器是可遍历的,可以使用
for循环等结构来进行遍历。
下面的代码可以看出迭代器在节省内存方面的作用。
import sys
import random# 生成 1-100的随机数的集合,共1000个元素
numbers = [random.randint(1, 100) for _ in range(1000)]
iterator = iter(numbers)# 打印对象的内存大小
print(sys.getsizeof(numbers)) # 9016
print(sys.getsizeof(iterator)) # 48
迭代器的经典demo:
# 创建一个简单的迭代器
class MyIterator:def __init__(self, limit):self.limit = limitself.current = 0def __iter__(self):return selfdef __next__(self):if self.current < self.limit:self.current += 1return self.currentelse:raise StopIteration# 使用迭代器
for num in MyIterator(5):print(num)
迭代器在读取大文件的经典应用:
with open('users.csv', 'r') as file:for line in file:print(line.strip())
逐行读取文件内容,而不需要将整个文件加载到内存中。这种方法节省了内存资源,特别是在处理非常大的文件时。
生成器
生成器是一种特殊类型的迭代器,它允许你在函数中暂停执行并在以后继续。
使用 yield 的基本概念
-
生成器函数:当一个函数包含
yield语句时,它不再是一个普通的函数,而是一个生成器函数。当调用这个函数时,它不会立即执行,而是返回一个生成器对象。 -
状态保留:每次调用生成器的
__next__()方法(或者使用next()函数)时,生成器函数会从上次执行的位置继续执行,直到遇到下一个yield语句。在此时,函数的执行状态(包括局部变量)会被保留。 -
迭代:生成器可以被用于迭代,像普通的列表或其他可迭代对象一样。使用
for循环可以逐个获取生成器产生的值。
# 定义一个生成器函数
def read_users():with open('users.csv', 'r') as file:for line in file:yield line.strip()r1 = read_users() # 定义一个生成器对象
r2 = read_users() # 定义另一个生成器对象
print(next(r1))
print(next(r1))
print(next(r1))
print(next(r1))
print(next(r2))
print(next(r2))
print(next(r2))
print(next(r2))
局部变量保留的demo
list1 = ['a', 'b', 'c', 'd', 'e', 'f']def iterator():i = 0for x in list1:yield do_something(i, x)i += 1def do_something(i, x):print(i, x)r1 = iterator() # 定义一个生成器对象
r2 = iterator() # 定义另一个生成器对象
next(r1)
next(r1)
next(r1)
next(r1)
next(r2)
next(r2)
next(r2)
next(r2)
next(r2)
运行结果:
0 a
1 b
2 c
3 d
0 a
1 b
2 c
3 d
4 e
更深入理解yield的“暂停”
函数每次遇到yield就暂停,它并不在意yield时来自于循环、迭代或者是在函数体内重复定义的,这意味着一个函数中可以有不止一个yield,并且每次运行到yield时,函数就暂停运行,并保存中间结果和变量,直到下一次next()后继续运行。
list1 = ['a', 'b', 'c', 'd', 'e', 'f']def iterator():for x in list1:yield print(x)yield print(x)yield print(x)yield print(x)r1 = iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
next(r1)
next(r1)
next(r1)# 运行结果:
# a
# a
# a
# a
# b
# b
可以将yield理解为一个中断标志
可以将yield理解为一个中断标志,当生成器遇到 yield 语句时,它会暂停执行,并返回 yield 后面跟随的值或者函数。如果yield后面没有跟随内容,那么它就仅仅是一次暂停标志而已。
list1 = ['a', 'b', 'c', 'd', 'e', 'f']def iterator():i = 0for x in list1:print('loop', i)yieldi += 1print(x)r1 = iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
# 执行结果:
# loop 0
# a
# loop 1
# b
# loop 2
yield的灵活运用
既然函数每次遇到yield就暂停,它并不在意yield时来自于循环、迭代或者是在函数体内重复定义的,而且可以将yield理解为一个中断标志,那么我们也就可以生成一个不循环的函数,通过yield达到步进执行的效果。
list1 = ['a', 'b', 'c', 'd', 'e', 'f']def iterator():i = 0print('breakpoint', i)yieldi += 1print('breakpoint', i)yieldi += 1print('breakpoint', i)yieldi += 1print('breakpoint', i)yieldi += 1print('breakpoint', i)r1 = iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
# 执行结果:
# breakpoint 0
# breakpoint 1
# breakpoint 2
注意可暂停和可迭代次数
要保证调用的次数不要大于可迭代次数或者可暂停次数,否则就会报错。
def iterator():i = 0print('breakpoint', i)i += 1yieldprint('breakpoint', i)i += 1yieldr1 = iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
上面的例子,定义了两个yield,但是next()调用了三次,所以出错。
list1 = [1, 2, 3]def iterator():for i in list1: # 遍历列表yield print(i)r1 = iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
next(r1)
这个,由于调用次数大于了列表的元素数量,也会出错。
采取措施,避免程序崩溃
1、使用try
def iterator():i = 0print('breakpoint', i)i += 1yieldprint('breakpoint', i)i += 1yieldr1 = iterator() # 定义一个生成器对象def next_do():try:next(r1)except StopIteration:print("No more items to yield")next_do()
next_do()
next_do()
next_do()
list1 = [1, 2, 3]def iterator():for i in list1: # 遍历列表yield print(i)r1 = iterator() # 定义一个生成器对象def next_do():try:next(r1)except StopIteration:print("No more items to yield")next_do()
next_do()
next_do()
next_do()
next_do()# 运行结果:
# 1
# 2
# 3
# No more items to yield
# No more items to yield
2、指定next()的默认返回值参数,如果指定了该参数,并且迭代器没有更多的值可返回,则返回该参数的值,而不是引发 StopIteration 异常。
def iterator():i = 0print('breakpoint', i)i += 1yieldprint('breakpoint', i)i += 1yielddef next_do():if next(r1, 'END'): # 指定next()的默认返回值,可以是任意非None值print('No more items to yield')r1 = iterator() # 定义一个生成器对象next_do()
next_do()
next_do()
next_do()
next_do()# 运行结果:
# breakpoint 0
# breakpoint 1
# No more items to yield
# No more items to yield
# No more items to yield
send()的用法
def generator_with_send():received = yield # yield 语句会暂停生成器,等待 send() 方法的调用并返回 yield 语句后面的值yield received # 输出接收到的值gen = generator_with_send()next(gen) # 启动生成器
print(gen.send('this is send1')) # 通过 send() 方法向生成器发送数据
多次发送
def generator_with_send():received = yield # 第一次调用 `send` 时暂停在此处yield received # 输出第一次接收到的值received = yield # 再次暂停,准备接收下一个值yield received # 输出第二次接收到的值received = yield # 再次暂停,准备接收下一个值yield received # 输出第三次接收到的值gen = generator_with_send()next(gen) # 启动生成器
print(gen.send('this is send1')) # 发送数据
next(gen) # 继续执行,准备接收下一个值
print(gen.send('this is send2')) # 发送数据
next(gen) # 继续执行,准备接收下一个值
print(gen.send('this is send3')) # 发送数据# 输出结果为:
# this is send1
# this is send2
# this is send3
OR:
def generator_with_send():received = yield # 第一次调用 `send` 时暂停在此处received = yield received # 每次重新接收 send() 发送的值received = yield received # 每次重新接收 send() 发送的值received = yield received # 每次重新接收 send() 发送的值gen = generator_with_send()next(gen) # 启动生成器
print(gen.send('this is send1')) # 第一次发送 'this is send1'
print(gen.send('this is send2')) # 第二次发送 'this is send2'
print(gen.send('this is send3')) # 第三次发送 'this is send3'
OR:
def generator_with_send():received = yield # 第一次调用 `send` 时暂停在此处while True:received = yield received # 每次重新接收 send() 发送的值gen = generator_with_send()next(gen) # 启动生成器
print(gen.send('this is send1')) # 第一次发送 'this is send1'
print(gen.send('this is send2')) # 第二次发送 'this is send2'
print(gen.send('this is send3')) # 第三次发送 'this is send3'
close()的用法
close()方法用于关闭生成器,关闭后,如果尝试迭代或恢复执行生成器,会引发 StopIteration 异常。
在生成器中,close() 方法会触发 GeneratorExit 异常,通过捕捉这个异常,在生成器中进行必要的清理工作(比如释放资源、关闭文件等)。
def my_generator():try:while True:value = yieldprint(f"Received: {value}")except GeneratorExit:print("Generator is being closed.")gen = my_generator()# 启动生成器
next(gen)# 发送一些值
gen.send('Hello')
gen.send('World')# 关闭生成器
gen.close()# 再次尝试发送值会引发 StopIteration 异常
try:gen.send('This will not work')
except StopIteration:print("Generator is closed and cannot receive values.")
相关文章:
迭代器和生成器的学习笔记
迭代器 Python 迭代器是一种对象,它实现了迭代协议,包括 __iter__() 和 __next__() 方法。迭代器可以让你在数据集中逐个访问元素,而无需关心数据结构的底层实现。与列表或其他集合相比,迭代器可以节省内存,因…...
ES5 在 Web 上的现状
最后一个支持 ES5 的浏览器 IE 11 在 2022 年被微软停止支持,那么今天 Web 上的 ES5 现状如何?在构建生产代码时,Web 开发者的最佳实践是什么? 本文将通过数据来回答这些问题,并基于这些数据为网站开发者和库作者提供一…...
人话学Python-循环语句
一:while语句 while语句的组成由判断条件和执行语句组成。当满足条件时会不断执行后续语句,然后再循环执行的语句结束之后再次回到条件判断,如此循环。 pos 0 ans 0 while pos < 6:ans pos * 4pos 1 print(ans)>>>84"&…...
初识模版!!
初识模版 1.泛型编程1.1 如何实现一个交换函数呢(使得所有数据都可以交换)?1.2 那可以不可以让编译器根据不同的类型利用该模子来生成代码呢? 2.模版类型2.1 模版概念2.2 函数模版的原理2.3 函数模板的实例化2.4 模板参数的匹配原…...
算法之数学--hash算法 2021-03-11(未完待续)
1.hash算法 刷出一道墙 题目描述 Time Limit: 2000 ms Memory Limit: 256 mb 在一面很长的墙壁上,工人们用不同的油漆去刷墙,然而可能有些地方刷过以后觉得不好看,他们会重新刷一下。有些部分因为重复刷了很多次覆盖了很多层油漆ÿ…...
DHCP工作原理
在学习之前先提出几个问题:什么是DHCP?为什么要使用DHCP?在什么场景中使用DHCP?DHCP报文的目的IP和目的MAC是多少?DHCP报文是基于UDP还是基于TCP?DHCP服务器返回的报文中都包含什么信息? DHCP&a…...
服务发现和代理实例的自动更新
☞ 返回总目录 1.服务发现的两种方式 StartFindService 方法 这是一个在后台启动的连续 “FindService” 活动,当服务实例的可用性发生变化时,会通过回调通知调用者。 它返回一个FindServiceHandle,可通过调用StopFindService来停止正在进行…...
Redis的三种持久化方法详解
Redis持久化机制详解 | JavaGuide Redis 不同于 Memcached 的很重要一点就是,Redis 支持持久化,而且支持 3 种持久化方式: 快照(snapshotting,RDB)只追加文件(append-only file, AOF)RDB 和 A…...
OpenAI GPT o1技术报告阅读(5)-安全性对齐以及思维链等的综合评估与思考
✨继续阅读报告:使用大模型来学习推理(Reason) 原文链接:https://openai.com/index/learning-to-reason-with-llms/ 编码 我们训练了一个模型,在2024年国际信息学奥林匹克竞赛(IOI)中得分213分,排名在第…...
nodejs 012:Babel(巴别塔)语言转换与代码兼容
这里写目录标题 安装 Babel配置presets配置:常见的 Babel Presetsplugins配置:以 plugin-transform-class-properties 的类中属性为例index.jsx Babel 是一个独立的 JavaScript 编译器,主要用于将现代 JavaScript 代码转换为旧版本的 JavaScr…...
时间安全精细化管理平台存在未授权访问漏洞
漏洞描述 登录--时间&安全精细化管理平台存在未授权访问漏洞导致与员工信息泄露 FOFA: body"登录--时间&安全精细化管理平台" 漏洞复现 POC: IP/acc/_checkinoutlog_/...
软件卸载工具(windows系统)-geek
有时候软件卸载会很麻烦,使用geek会比较方便。但是针对一些特别大的软件,geek也好像会稍微费点劲(比如MATLAB2022A),不过针对一般常规软件的卸载,geek就可以有效地完全卸载了,使用方法也很简单,…...
第三篇 第14篇 工程计价依据
第三篇 工程计价 第14篇 工程计价依据 14.1 工程造价管理标准体系与工程定额体系 14.1.1 工程造价管理标准体系 1.基础标准 工程造价术语标准建筑工程计价设备材料划分标准有关建设工程费用构成通则。建设工程费用构成和分类是工程计价最重要的基础工作。 2.管理规范 建筑…...
java 异常-Exception
异常的概念 Java 语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常) 执行过程中所发生的异常事件可分为两大类 (1)Error(错误):Java 虚…...
爬虫逆向学习(六):补环境过某数四代
声明:本篇文章内容是整理并分享在学习网上各位大佬的优秀知识后的实战与踩坑记录 引用博客: https://blog.csdn.net/shayuchaor/article/details/103629294 https://blog.csdn.net/qq_36291294/article/details/128600583 https://blog.csdn.net/weixin_…...
IO流体系(FiletOutputStream)
书写步骤: 1.创建字节输出流对象 细节1:参数是字符串表示的路径或者是File对象都是可以的 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。 细节3:如果文件已经存在,则会清空文件 2.写数据 细节:write方法的参数…...
网络设备登录——《路由与交换技术》实验报告
目录 一、实验目的 二、实验设备和环境 三、实验记录 1.通过 Console 登录 步骤1:连接配置电缆。 步骤2:启动PC,运行超级终端。 步骤3:进入Console 配置界面 2.通过 Telnet 登录 步骤1:通过 Console 接口配置 Telnet 用户。 步骤2:配置 super 口令 步骤3:配置登录欢迎…...
CSS——网格布局(display: grid)之下篇
CSS——网格布局(display: grid)之下篇 前面我们介绍了网格布局的基础的创建以及一些比较基础的属性,下面我们将介绍网格布局的剩余部分,还将结合实例来进行细致的讲解(图文并茂,生动形象有内涵࿰…...
低势期操作
《周易》讲事务发展有六个阶段: 第一阶段:潜龙勿用。 第二阶段:见龙在田。 第三阶段:终日乾乾。 第四阶段:或跃在渊。 第五阶段:飞龙在天。 第六阶段:亢龙有悔。 现在大环境不好ÿ…...
IMS 呼叫流程(详细)
目录 业务模型 典型组网如图1所示 信令流程 具体的语音流程如图2所示 主叫信令面流程 01:UE_A->P-CSCF/ATCF 02:P-CSCF/ATCF_A->PCRF_A 03:PCRF_A->PCSCF/ATCF_A 04:P-CSCF/ATCF_A 处理(把S-CSCF加到Route) 05:S-CSCF_A->MMTel AS/SCC AS_A 06:MM…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
