Python 迭代器与生成器:从协议到实战,一篇讲透
迭代器Iterator和生成器Generator是 Python 中两个紧密相关但常被混淆的概念。很多人会用for循环但对它们背后的工作机制却模糊不清。这篇文章从协议规范到内存模型再到实战场景把迭代器和生成器彻底讲清楚。一、迭代器协议Python 的 for 循环到底怎么工作的在 Python 中可迭代对象Iterable和迭代器Iterator是两个不同的概念可迭代对象实现了__iter__()方法返回一个迭代器迭代器实现了__iter__()和__next__()两个方法pythonfrom typing import Iterator, Iterable class MyRange: 自定义可迭代对象 def __init__(self, start: int, end: int): self.start start self.end end def __iter__(self) - Iterator[int]: return MyRangeIterator(self.start, self.end) class MyRangeIterator: 自定义迭代器 def __init__(self, current: int, end: int): self.current current self.end end def __iter__(self): return self def __next__(self) - int: if self.current self.end: raise StopIteration value self.current self.current 1 return value # 使用 for i in MyRange(0, 5): print(i) # 0, 1, 2, 3, 4for循环的背后python# Python 执行 for i in obj 时实际做了这些事 iterator iter(obj) # 调用 obj.__iter__() while True: try: i next(iterator) # 调用 iterator.__next__() except StopIteration: break # 迭代结束 # 执行循环体...关键理解可迭代对象是数据容器如 list、dict、set迭代器是数据游标记录当前遍历位置每次for循环都会通过iter()获取一个新的迭代器二、生成器用函数写迭代器生成器是用函数语法写迭代器的快捷方式。只要函数里用了yield它就变成生成器函数调用时返回生成器对象一种特殊的迭代器。pythondef my_range(start: int, end: int): 生成器版本的范围函数 current start while current end: yield current current 1 # 调用返回生成器对象 gen my_range(0, 5) print(type(gen)) # class generator for i in gen: print(i) # 0, 1, 2, 3, 4代码量对比方案代码行数需要维护的状态手写迭代器类~15 行__iter__、__next__、StopIteration生成器函数~5 行只需yield生成器的优势写法简洁不需要定义类和实现协议方法状态自动保存yield会保存当前局部变量、指令指针、调用栈惰性求值数据按需生成不一次性加载到内存三、生成器的执行模型yield 到底做了什么理解yield的执行流程是关键pythondef demo(): print(1. 开始执行) yield A print(2. yield 后继续) yield B print(3. 函数结束) gen demo() print(next(gen)) # 打印 1. 开始执行 → 返回 A print(next(gen)) # 从 yield A 后继续 → 打印 2. yield 后继续 → 返回 B print(next(gen)) # 从 yield B 后继续 → 打印 3. 函数结束 → 抛出 StopIteration执行流程text调用 demo() → 返回生成器对象函数体还未执行 第一次 next(gen) → 执行到 yield A → 暂停并返回 A 第二次 next(gen) → 从暂停位置继续 → 执行到 yield B → 暂停并返回 B 第三次 next(gen) → 从暂停位置继续 → 执行完毕 → 抛出 StopIteration关键理解yield既返回值又暂停执行。生成器函数的执行权在调用方和生成器之间交替。四、生成器的进阶用法send、throw、close4.1send()向生成器发送值send(value)可以向生成器传入一个值这个值会成为当前yield表达式的返回值。pythondef accumulator(): total 0 while True: value yield total # yield 返回 total同时接收外部传入的值 if value is None: break total value acc accumulator() next(acc) # 启动生成器执行到 yield total返回 0 print(acc.send(10)) # 传入 10total10执行到 yield total返回 10 print(acc.send(20)) # 传入 20total30执行到 yield total返回 30 acc.close() # 关闭生成器next(gen)等价于gen.send(None)所以必须先next()启动。实战场景协程、数据管道、交互式处理。4.2throw()向生成器抛出异常pythondef safe_processor(): try: while True: value yield print(f处理: {value}) except ValueError: print(收到 ValueError跳过当前数据) except GeneratorExit: print(生成器被关闭) gen safe_processor() next(gen) # 启动 gen.send(10) # 处理: 10 gen.throw(ValueError) # 收到 ValueError跳过当前数据 gen.send(20) # 处理: 20生成器继续工作 gen.close() # 生成器被关闭4.3close()提前终止生成器pythondef infinite_sequence(): n 0 try: while True: yield n n 1 except GeneratorExit: print(生成器被关闭清理资源...) gen infinite_sequence() print(next(gen)) # 0 print(next(gen)) # 1 gen.close() # 生成器被关闭清理资源... # next(gen) # 再调用会抛出 StopIteration最佳实践如果生成器持有文件句柄、网络连接等资源用try/finally或捕获GeneratorExit做清理。五、生成器表达式惰性版的列表推导式python# 列表推导式立即计算占用内存 squares_list [x**2 for x in range(10000000)] # 立即创建 1000 万个元素的列表 # 生成器表达式惰性计算不占内存 squares_gen (x**2 for x in range(10000000)) # 只返回生成器对象不计算 # 按需取值 print(next(squares_gen)) # 0 print(next(squares_gen)) # 1语法区别写法类型内存占用是否可复用[x**2 for x in range(10)]list高是(x**2 for x in range(10))generator低否注意生成器是一次性的。迭代完后再遍历不会产生任何值pythongen (x for x in range(3)) print(list(gen)) # [0, 1, 2] print(list(gen)) # [] 第二次为空六、实战场景生成器解决真实问题场景一处理超大日志文件pythondef tail_log(filepath: str, keyword: str): 实时跟踪日志文件过滤包含关键词的行 with open(filepath, r, encodingutf-8) as f: # 跳到文件末尾 f.seek(0, 2) while True: line f.readline() if not line: import time time.sleep(0.1) continue if keyword in line: yield line.strip() # 使用 for line in tail_log(/var/log/app.log, ERROR): print(f发现异常: {line}) if FATAL in line: break # 可随时停止场景二分页拉取 API 数据带限流pythonimport time import requests from typing import Generator, Dict, Any def paginated_api(base_url: str, page_size: int 50, rate_limit: float 1.0) - Generator[Dict[str, Any], None, None]: 分页拉取 API 数据支持限流 page 1 while True: resp requests.get( base_url, params{page: page, size: page_size}, timeout10 ) resp.raise_for_status() data resp.json() if not data.get(items): break for item in data[items]: yield item # 检查是否最后一页 if page data.get(total_pages, float(inf)): break page 1 time.sleep(rate_limit) # 限流 # 使用方完全不用关心页码和限流 for user in paginated_api(https://api.example.com/users): print(user[name]) if user[id] 1000: break场景三管道式数据处理pythondef read_numbers(n: int): for i in range(n): yield i def even_only(source): for num in source: if num % 2 0: yield num def square(source): for num in source: yield num * num def take(source, n: int): count 0 for item in source: if count n: break yield item count 1 # 链式组合取 100 以内偶数的平方取前 5 个 pipeline take(square(even_only(read_numbers(100))), 5) print(list(pipeline)) # [0, 4, 16, 36, 64]每个环节只做一件事数据惰性流动没有中间列表产生。七、迭代器 vs 生成器一句话对比对比维度迭代器生成器定义方式实现__iter____next__函数中有yield代码量较多需定义类较少函数即可状态管理手动维护实例变量自动保存局部变量可复用性可多次迭代重新创建实例一次性双向通信不支持支持send()/throw()适用场景需要封装复杂迭代逻辑大部分迭代场景八、记忆口诀迭代器是协议生成器是语法糖yield 暂停又返回next 驱动向前闯惰性求值省内存管道组合威力强。总结迭代器是实现了__iter__和__next__的对象是for循环的基础生成器是用yield写迭代器的快捷方式自动保存状态生成器表达式是惰性版的列表推导式节省内存send()、throw()、close()是生成器的进阶控制能力处理大文件、流式数据、管道组合时优先考虑生成器本文为纯技术分享不涉及任何品牌或产品。

相关新闻

Stable Diffusion机甲模型SDX SUPER G-ARMS实战指南

Stable Diffusion机甲模型SDX SUPER G-ARMS实战指南

1. 先搞清楚这个模型到底能做什么 看到“SDX 限定版 SUPER G-ARMS 最终式样”这个标题,很多人第一反应可能是某个游戏模组或动漫周边。但如果你关注过 Stable Diffusion 模型社区,就会知道这其实是一个针对特定机甲题材训练的风格化模型。这类模型最大的…

2026/10/2 2:45:58 阅读更多 →
Unity全平台PDF渲染插件集成指南:从UI到3D物体的完整解决方案

Unity全平台PDF渲染插件集成指南:从UI到3D物体的完整解决方案

1. 项目概述与核心价值 在Unity项目里展示PDF,这事儿听起来简单,但真做起来,你会发现它是个典型的“需求不大,坑却不少”的活儿。无论是做教育类应用需要展示电子教材,做企业工具需要预览合同文档,还是做AR…

2026/10/8 19:44:43 阅读更多 →
五款主流防伪认证芯片横向对比:从 1-Wire 到 PUF

五款主流防伪认证芯片横向对比:从 1-Wire 到 PUF

给配件选防伪芯片,圈子里绕不开几颗经典型号。把资料翻了一遍,结合自己用过和评估过的型号,从认证机制、算法、接口、功耗几个维度做个梳理,方便选型时对照。五颗芯片的基本盘型号厂商认证机制算法接口特点ATSHA204AMicrochip对称…

2026/10/9 8:57:39 阅读更多 →

最新新闻

高性能HMI设计:从界面到系统的工业视觉革命

高性能HMI设计:从界面到系统的工业视觉革命

做工业项目这么多年,只要现场出问题,第一个被拉出来“背锅”的往往不是PLC,不是伺服,而是那块天天被人盯着的屏幕——HMI。我最近常跟同行聊“HMI视觉革命”,大家都意识到一件事:高性能HMI不是锦上添花&…

2026/10/12 10:47:47 阅读更多 →
Android多屏壁纸机制解析:从displayId到折叠屏适配实践

Android多屏壁纸机制解析:从displayId到折叠屏适配实践

最近在适配一台折叠屏设备时碰到一个问题:设备合上盖子,外屏壁纸显示正常;展开之后,内屏反而变成了系统默认的纯色背景。一开始以为是主题资源配色的问题,查了一整天,最后把思路拉回到安卓系统里Wallpaper与…

2026/10/12 10:47:47 阅读更多 →
纯NumPy手写深度神经网络:从零实现DNN核心模块与训练全流程

纯NumPy手写深度神经网络:从零实现DNN核心模块与训练全流程

深度神经网络这个词,这几年被说得太多了,以至于很多刚入行的朋友觉得它很玄。但如果你真正动手用Python从零搭过一个能跑起来的DNN,你会发现它的本质其实非常朴素——一堆矩阵乘法、几个非线性激活函数、一套反向传播的链式求导,再…

2026/10/12 10:47:47 阅读更多 →
Django购物商城开发全解析:从ORM建模到订单支付与答辩加分项

Django购物商城开发全解析:从ORM建模到订单支付与答辩加分项

1. 项目整体设计与技术选型:为什么用 Django 做购物商城 做电商类毕设,很多同学第一个纠结的问题就是:语言和框架到底选什么。我给出的建议很直接——如果你没有特别强烈的偏好,Django 是综合性价比最高的选择。这个结论不是拍脑袋…

2026/10/12 10:47:47 阅读更多 →
Django蛋糕商城毕设实战:需求拆解、购物车与订单实现要点

Django蛋糕商城毕设实战:需求拆解、购物车与订单实现要点

这标题一看就是最常见的毕业设计款式——基于Django的蛋糕购物商城网站的设计与实现。它听起来简单,但实际上是Django全栈项目里相当典型的一套组合:要做用户体系、商品展示、购物车、订单流转,还要有一个后台管理界面来维护商品库存和订单状…

2026/10/12 10:47:47 阅读更多 →
摩托车检测数据集:3661张真实图像+YOLO/VOC双格式标签

摩托车检测数据集:3661张真实图像+YOLO/VOC双格式标签

简介:本资源是一份专为计算机视觉目标检测任务设计的摩托车检测数据集,面向深度学习初学者、YOLO系列算法实践者及智能交通相关项目开发者,可直接用于模型训练、验证与部署。数据集基于COCO2017权威数据源提取构建,统一标注为单一…

2026/10/12 10:46:46 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →