当前位置: 首页 > news >正文

AI_Python基础-6.迭代器与生成器

Python 迭代器与生成器

标签: #Python #迭代器 #生成器 #yield #延迟计算
学习周期:1 天 | 核心目标:理解迭代协议,掌握生成器实现延迟计算,对比列表推导式与生成器表达式的内存差异


3.2 迭代器与生成器

迭代器与生成器是 Python 中高效处理序列数据的核心工具,核心优势是延迟计算(惰性求值)—— 不一次性生成所有数据,而是按需生成,大幅节省内存(尤其适合处理海量数据)。


3.2.1 可迭代对象(__iter__)与迭代器(__next__

核心概念对比
类型核心特征关键方法示例
可迭代对象能被for循环遍历,可生成迭代器__iter__():返回迭代器liststrtupledictset
迭代器可逐个返回元素,可记录遍历位置,只能遍历一次__next__():返回下一个元素;__iter__():返回自身iter(list)、文件对象、生成器对象
判断可迭代对象和迭代器
fromcollections.abcimportIterable,Iterator lst=[1,2,3]print(isinstance(lst,Iterable))# True(可迭代)print(isinstance(lst,Iterator))# False(不是迭代器)it=iter(lst)# 获取迭代器print(isinstance(it,Iterator))# True
手动使用迭代器
lst=[1,2,3]it=iter(lst)# 获取迭代器print(next(it))# 1print(next(it))# 2print(next(it))# 3# print(next(it)) # StopIteration 异常
for循环的工作原理
# for 循环等价于:it=iter(可迭代对象)whileTrue:try:value=next(it)# 执行循环体exceptStopIteration:break
自定义迭代器
classMyIterator:def__init__(self,start,end):self.current=start self.end=enddef__iter__(self):returnselfdef__next__(self):ifself.current>self.end:raiseStopIteration temp=self.current self.current+=1returntemp my_iter=MyIterator(1,3)fornuminmy_iter:print(num)# 1, 2, 3# 再次遍历(迭代器已耗尽,无输出)fornuminmy_iter:print(num)
易错点说明
  • 可迭代对象 ≠ 迭代器:可迭代对象需要通过iter()转换为迭代器才能手动遍历。
  • 迭代器只能遍历一次:遍历结束后指针停在最后,无法重置,需重新创建迭代器。
  • for循环的底层逻辑:先调用iter(可迭代对象)生成迭代器,再循环调用next(),直到捕获StopIteration异常,自动终止循环。

3.2.2 生成器函数(yield)—— 延迟计算,节省内存

生成器是一种特殊的迭代器,使用yield关键字定义。生成器函数在每次调用next()时执行到yield暂停并返回一个值,下次调用从暂停处继续。

核心特性
  • 延迟计算:只在需要时生成值,节省内存。
  • 状态保持:函数内的局部变量在每次yield之间保持。
  • 无限序列:可以表示无限大的序列(如斐波那契数列)。
基本用法
defmy_generator(start,end):current=startwhilecurrent<=end:yieldcurrent current+=1gen=my_generator(1,3)# 创建生成器对象,函数体不会立即执行print(type(gen))# <class 'generator'>print(isinstance(gen,Iterator))# True# 手动遍历print(next(gen))# 1print(next(gen))# 2print(next(gen))# 3# print(next(gen)) # StopIteration# for 循环遍历(推荐)fornuminmy_generator(1,3):print(num)# 1, 2, 3
生成器实现斐波那契数列(节省内存)
deffibonacci(limit):a,b=0,1whilea<limit:yielda a,b=b,a+bfornuminfibonacci(100):print(num,end=" ")# 0 1 1 2 3 5 8 13 21 34 55 89
生成器的进阶方法(sendclose
defecho():whileTrue:received=yieldprint(f"收到:{received}")gen=echo()next(gen)# 预激生成器,执行到第一个 yieldgen.send("Hello")# 收到:Hellogen.send("World")# 收到:Worldgen.close()# 关闭生成器
应用场景
  • 处理海量数据(如读取超大文件、生成百万级随机数),避免内存溢出。
  • 惰性计算场景:批量处理数据,不需要一次性获取所有结果。
  • 替代列表推导式:当数据量较大时,用生成器替代列表推导式。

3.2.3 生成器表达式

生成器表达式类似于列表推导式,但使用圆括号()而不是方括号[]。它返回一个生成器对象,而不是一次性创建列表,适合处理大量数据。

语法
(expressionforiteminiterableifcondition)
示例与对比
# 列表推导式:立即生成所有值,占用内存squares_list=[x**2forxinrange(10)]print(squares_list)# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]# 生成器表达式:延迟计算,不占内存squares_gen=(x**2forxinrange(10))print(squares_gen)# <generator object <genexpr> at 0x...>forvalinsquares_gen:print(val,end=" ")# 0 1 4 9 16 25 36 49 64 81# 一次性转换为列表(失去生成器的优势)squares_list2=list(x**2forxinrange(10))
内存对比
importsys# 列表推导式:立即分配内存list_comp=[xforxinrange(1000000)]print(sys.getsizeof(list_comp))# 约 8 MB# 生成器表达式:几乎不占内存gen_exp=(xforxinrange(1000000))print(sys.getsizeof(gen_exp))# 约 104 字节
与高阶函数配合
# 计算 1 到 1e6 的平方和(无需创建巨大列表)total=sum(x**2forxinrange(1,1000001))print(total)# 找出 1 到 1e6 中能被 7 整除的最大数max_val=max(xforxinrange(1,1000001)ifx%7==0)print(max_val)
实战场景:逐行读取大文件
defread_large_file(file_path):return(line.strip()forlineinopen(file_path,"r",encoding="utf-8"))# 使用:按需读取,内存占用极低forlineinread_large_file("large_file.txt"):print(line)# 逐行处理
易错点说明
  • 生成器表达式的圆括号不能省略,否则会变成普通表达式。
  • 生成器表达式也是“一次性的”,遍历结束后无法重复使用,需重新定义。
  • 数据量小且需要多次访问时用列表推导式;数据量大且只需遍历一次时用生成器表达式。

3.2.4 迭代器、生成器与列表推导式的选择

场景推荐方案原因
数据量小,需要多次遍历列表推导式值已存储在内存中,访问快
数据量大,只需遍历一次生成器表达式或生成器函数节省内存,延迟计算
需要复杂逻辑控制生成器函数(yield可暂停、保持状态,代码清晰
需要向生成器发送数据生成器函数 +send()双向通信

📚 学习资料(Obsidian 可直接收藏)

  • 官方文档
    Python 迭代器协议
    Python 生成器
    yield 表达式
    生成器表达式

  • 中文教程
    廖雪峰 - 迭代器与生成器
    菜鸟教程 - 迭代器与生成器

  • 视频推荐
    Python 生成器详解(B站)


🎯 学习建议(1 天计划)

  1. 上午:理解可迭代对象与迭代器的区别,手动实现__iter____next__,练习生成器函数(yield)。
  2. 下午:掌握生成器表达式,对比列表推导式的内存占用,完成实战练习(大文件读取、无限序列生成)。

✅ 核心要点总结

  1. 可迭代对象:实现了__iter__(),返回迭代器。常见的有liststrdict等。
  2. 迭代器:实现了__iter__()__next__(),只能遍历一次。for循环依赖迭代协议。
  3. 生成器函数:使用yield的函数,调用时返回生成器对象(属于迭代器),支持延迟计算和状态保持。
  4. 生成器表达式:类似列表推导式但使用(),返回生成器对象,适合大数据量处理。
  5. 内存优势:生成器和生成器表达式不一次性存储所有元素,处理大数据集时能显著降低内存占用。
  6. 一次性特点:生成器和迭代器都只能遍历一次,无法重置。

练习题(自测)

  1. 定义一个可迭代对象Fibonacci,使用__iter____next__实现斐波那契数列的前n项。
  2. 编写生成器函数read_large_file(file_path),逐行读取大文件(模拟),每次yield一行。
  3. 使用生成器表达式找出 1 到 100000 中所有能被 13 整除的数,并计算它们的和(不使用列表)。
  4. 实现一个无限生成器cycle(iterable),无限循环返回可迭代对象中的元素(如cycle('AB')输出A B A B ...)。
  5. 写一个生成器primes(),无限产生素数(使用埃拉托斯特尼筛法或试除法)。

建议在 Jupyter Notebook 或本地环境中运行,比较生成器和列表推导式的内存差异。

http://www.jsqmd.com/news/894202/

相关文章:

  • 从青岛验潮站到你的手机地图:聊聊‘海拔’背后的故事与1985高程基准的诞生
  • 别再为打印样式头疼了!用vue-print-nb搞定A4纸精确排版(附完整CSS代码)
  • 【权威实测】ChatGPT教育优惠申请成功率从31%→98%的关键转折点:我们逆向分析了OpenAI后台审核逻辑
  • 2026年4月灯座制造工厂怎么选择,复古风格灯座,增添家居韵味 - 品牌推荐师
  • IMX6ULL的Linux内核移植
  • 【C++进阶】vector 类从入门到精通:核心接口与内存机制实战指南
  • 【职场】关于职场“老实人“,你不知道的10个真相
  • AI精准农业杂草管理系统:YOLO11n与Jetson Orin的实践
  • 【AI Agent 开发实战·第01讲】从“缸中之脑”到“全能助手”:为什么我们需要 AI Agent?它与 ChatGPT 有什么本质区别?
  • 2026年主流种公猪基因厂家地址及核心实力评测:美系公猪哪个品牌好、蓝耳伪狂双阴性正规猪精厂家、顶王金猪、黑猪精哪个品牌好选择指南 - 优质品牌商家
  • 禾墩文化传播智慧二维码系统解析
  • 如何用AutoGen快速搭建Multi-Agent协作系统?实战指南
  • A-11-AI能做什么?盘点2026年AI的100种用法
  • 告别手写Shader!ShaderGraph可视化制作卡通风格水体(URP管线配置避坑)
  • 【求职】关于“跳槽“,你不知道的10个真相
  • 重磅!Erupt 1.14.3 发布:多个 AI 智能体在你的后台开始“组团打工“了
  • 从‘小费’到‘泰坦尼克’:用Seaborn的boxplot快速探索3个经典数据集的秘密与异常
  • Air1601 LCD 显示开发全解析
  • 扫地机器人行业 企业篇-追觅科技
  • 别再花钱找淘宝了!保姆级教程:Win10系统下AMEsim、Matlab、Visual Studio三件套一站式安装避坑指南
  • 2026年IPO资料可以用AI自动制作吗:投行文档自动化选型对比与落地清单 - 观域传媒
  • 别再右键属性了!Edge/Chrome/Firefox浏览器安装路径的3种隐藏查看法(含命令行版)
  • UE4开发者必看:解决Nvidia Ansel提示‘必须支持的游戏’错误,保姆级排查指南
  • 扫地机器人行业 企业篇-小米/米家
  • cmux:专为 AI 编程 Agent 打造的 macOS 终端神器
  • Node js 服务中集成 Taotoken 实现异步聊天补全的完整示例
  • Unity ShaderGraph实战:用Input节点5分钟搞定一个动态水面材质(附完整节点图)
  • 赋予网络物理直觉:一种多模态融合和物理敏感注意力的离心泵故障诊断(完善中......)
  • 8051中断优化:ONEREGBANK指令原理与实践
  • 课堂复刻|个人经验分享:Spring Boot整合MyBatis