迭代器和生成器的学习笔记
迭代器
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…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...