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

python 迭代器和生成器

参考资料: https://www.runoob.com/python3/python3-iterator-generator.html

Python 的迭代器(Iterator)生成器(Generator) 是实现惰性求值、节省内存的重要机制,二者密切相关,但有明确区别。下面分点说明:


一、迭代器(Iterator)

定义:

迭代器是一个实现了迭代器协议的对象,即同时具备以下两个方法:

  • __iter__():返回迭代器自身(必须);
  • __next__():返回序列中的下一个元素;若无更多元素,抛出 StopIteration 异常。
特点:
  • 一次性遍历(遍历完即“耗尽”);
  • 惰性求值:元素在需要时才生成(适用于大数据流或无限序列);
  • 可通过 iter() 函数从可迭代对象(如 list、str)获取其迭代器。
自定义迭代器(手动实现协议)

通过类实现 __iter__()__next__() 方法:

class CountIterator:def __init__(self, start, end):self.current = start  # 当前迭代值self.end = end        # 迭代终止条件def __iter__(self):return self  # 必须返回迭代器对象本身def __next__(self):if self.current > self.end:raise StopIteration  # 无元素时抛出异常,终止迭代res = self.currentself.current += 1return res# 使用迭代器
it = CountIterator(1, 3)
print(next(it))  # 1(手动调用 next())
print(next(it))  # 2
print(next(it))  # 3
print(next(it))  # 抛出 StopIteration
示例:
it = iter([1, 2, 3])		# 将可迭代对象转化未迭代器对象
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# next(it) → StopIteration

✅ 所有生成器都是迭代器,但并非所有迭代器都是生成器。


二、生成器(Generator)常用 yield

参考资料: https://www.runoob.com/python3/python3-iterator-generator.html

生成器是一种特殊的迭代器,由生成器函数(含 yield 表达式的函数)或生成器表达式创建。

****同步生成器(普通生成器)异步生成器
定义语法def + yield(普通函数)async def + yield(异步函数)
迭代协议实现「同步迭代协议」:- __iter__()返回自身- __next__()普通方法(阻塞)实现「异步迭代协议」:- __aiter__()回自身- __anext__()异步方法(async def,非阻塞)
迭代方式for循环或 next() 迭代必须用 async forawait anext() 迭代
内部支持操作只能调用同步函数(如 time.sleep
、普通 IO),调用异步函数会报错
可调用异步函数(如 await asyncio.sleep
、异步网络请求),也可混用同步操作
执行模型运行在当前线程,yield
暂停时阻塞线程(但切换成本低)
运行在事件循环,await
时释放事件循环,可并发处理其他任务(非阻塞)
暂停 / 恢复机制基于 Python 解释器的「生成器暂停机制」(保存局部变量、指令指针)结合「生成器暂停机制」+「异步事件循环调度」(await 时触发调度)
异常类型迭代结束抛 StopIteration迭代结束抛 StopAsyncIteration
资源释放支持 close()(同步)、throw()(同步抛异常)支持 aclose()(异步,需 await)、athrow()(异步抛异常,需 await
内存特性惰性生成,节省内存(和异步生成器一致)惰性生成,节省内存(核心共性)

2.1 同步生成器

2.1.1 single_yield

生成器函数中只有一个yield (常见)

样例1:

def single_yield_generator(n):      # 单个yield生成器函数i = 1while i <= n:yield ii += 1def test_yiled_for():for num in single_yield_generator(5):print(num)  # 输出:1 2 3 4 5# 单个yield生成器进行遍历
if __name__ == '__main__': # 使用test_yiled_for()

样例2:

单个yield生成器进行遍历,注意yield的返回时机, 每次yield就会返回,下次从yield的位置开始继续执行

def single_yield_generator(n):      # 单个yield生成器函数i = 1while i <= n:print("yield ........ before")yield iprint("yield ........ after")i += 1print("single_yield_generator 结束")def test_yiled_for():for num in single_yield_generator(5):# print("--------------------------begin")print(num)  # 输出:1 2 3 4 5print("--------------------------end")# 单个yield生成器进行遍历,注意yield的返回时机, 每次yield就会返回,下次从yield的位置开始继续执行
if __name__ == '__main__': # 使用test_yiled_for()

2.1.2 multi_yield

生成器函数包含多个yield (常见)

from loguru import loggerdef multi_yield_demo(a, b):caculate_sum = a + bprint(f"caculate_sum: {caculate_sum}")yield caculate_sum  # 第一次迭代返回,暂停caculate_sub = a - bprint(f"caculate_sub: {caculate_sub}")yield caculate_sub  # 第二次迭代返回,暂停caculate_multi = a * bprint(f"caculate_multi: {caculate_multi}")yield caculate_multi  # 第二次迭代返回,暂停# 如果一个函数中有多个yield, 那么每次迭代,yield 后面的表达式的值会返回给迭代器,并暂停,等待下一次迭代。 
# 下一次yield迭代会在上次暂停的地方继续执行,并返回值给迭代器。
if __name__ == '__main__': # 测试生成器gen = multi_yield_demo(5, 2)        # 获取得到一个生成器对象 class: generator# 方式1:用 next() 手动驱动print("next迭代:................................................")print(f"next迭代返回:{next(gen)}")  # 输出:执行到第一个 yield 前 → 第一个值print(f"next迭代返回:{next(gen)}")  # 输出:从第一个 yield 恢复,执行到第二个 yield 前 → 第二个值print(f"next迭代返回:{next(gen)}")  # 输出:从第二个 yield 恢复,执行到第三个 yield 前 → 第三个值try: # 无更多 yield,抛出 StopIterationZprint(f"next迭代返回:{next(gen)}")  # 输出:从第三个 yield 恢复,执行到第四个  except Exception as e: print(f"迭代异常:{type(e)}")# 方式2:用 for 循环自动迭代(推荐,无需处理 StopIteration)print("\nfor 循环迭代:................................................")for value in multi_yield_demo(5, 2):print(f"next迭代返回:{value}")

2.1.3 生成器 send用法

参考资料: https://www.runoob.com/python3/python3-iterator-generator.html

类似generator_obj.send(7)会先赋值到上一个yield退出的时候, 例如res = 7, 详细案例如下

def foo():print("starting...")while True:res = yield 4print("res:",res)# https://blog.csdn.net/mieleizhi0522/article/details/82142856
if __name__ == '__main__': generator_obj = foo()             # 这里返回一个生成器对象 不会调用函数  print(next(generator_obj))        # 返回第一个yield  start --> return 4  print("*" * 20)         # 分割.  print(generator_obj.send(7))      # 返回第二个yield  res = g.send(7), res = 7 在while循环中, 返回start就不会调用了 , 相当于先传值 然后next print("-" * 20 )print(next(generator_obj))        # 返回第三个yield  res, None --> return 4# 如果没有.send(7), 那么res, 默认就是None

2.1.4 next() 迭代生成器

1. 生成器函数
def count_up_to(n):i = 1while i <= n:yield ii += 1gen = count_up_to(3)
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
# next(gen) → StopIteration
  • 函数遇到 yield 时暂停执行,保存状态(局部变量、指令位置等);
  • 下次调用 next() 时从 yield 后继续执行;
  • 自动实现 __iter__()__next__(),因此是迭代器。
2. 生成器表达式(类似列表推导式,但用 ()
gen = (x**2 for x in range(3))
list(gen)  # [0, 1, 4]# 列表是可迭代对象,不是迭代器
def square_gen():for x in range(3):yield x**2  # 计算 x 的平方并返回# 等价于square_gen()
gen = (x**2 for x in range(3))      # 得到一个生成器对象for i in gen:print(i)square_g = square_gen()
print(list(square_g) )  # 第一遍遍历
print(list(square_g) )  # 第二遍为空
  • 比列表推导式更省内存(不一次性生成所有元素)。
  • 这行代码的目的是 演示生成器表达式的创建、惰性迭代特性,以及生成器 “一次性迭代” 的核心行为—— 第一次迭代获取所有结果,第二次迭代因生成器耗尽返回空列表。

2.2. 异步迭代器async for

2.2.1 single_yield

示例代码

import asyncio# 异步生成器(自动实现异步迭代器协议)
async def async_generator_single(start: int, end: int, delay: float = 0.2):current = startwhile current < end:await asyncio.sleep(delay)  # 模拟异步耗时操作yield current  # 异步返回值current += 1# 测试异步生成器
async def main():print(f"异步生成器迭代:")result_list = []async for num in async_generator_single(start=1, end=4):print(f"生成值:{num}")result_list.append(num)print(f"异步生成器迭代完成: {result_list}")# 生成器中包含多个yield
if __name__ == "__main__":asyncio.run(main())

2.2.2 multi_yield

示例代码

import asyncio# 异步生成器(自动实现异步迭代器协议)
async def async_generator_multi(start: int, end: int, delay: float = 0.2):current = startwhile current < end:await asyncio.sleep(delay)  # 模拟异步耗时操作yield current  # 异步返回值await asyncio.sleep(delay)  # 模拟异步耗时操作yield current + 1  # 异步返回值current += 1# 测试异步生成器
async def main():print(f"异步生成器迭代:")result_list = []async for num in async_generator_multi(start=1, end=4):print(f"生成值:{num}")result_list.append(num)print(f"异步生成器迭代完成: {result_list}")# 生成器中包含多个yield
if __name__ == "__main__":asyncio.run(main())

2.2.3 并行使用样例

  1. 这里是将异步生成器和恰如任务并行
import asyncio
import random
from datetime import datetime# 异步生成器(同上)
async def async_random_generator(count: int, delay: float = 1.0):print(f"[{datetime.now().strftime('%H:%M:%S')}] 异步生成器启动:生成 {count} 个随机数")for i in range(count):await asyncio.sleep(delay)random_num = random.uniform(0, 100)yield f"[{datetime.now().strftime('%H:%M:%S')}] 第 {i+1} 个随机数:{random_num:.2f}"# 另一个异步任务:每秒打印当前时间
async def task_print_time():"""每秒打印一次当前时间,共打印 6 次"""for i in range(5):print(f"[{datetime.now().strftime('%H:%M:%S')}] 当前时间(并发任务1).............task_print_time: {i}")await asyncio.sleep(1.0)async def consume_random_generator():async for res in async_random_generator(count=5):print(res)
# 主函数:并发运行两个异步任务
async def main():# 方式1:用 asyncio.gather 并发运行两个任务task1 = asyncio.create_task(task_print_time())                           # 并发任务1:打印时间task2 = asyncio.create_task(consume_random_generator())                  # 并发任务2:迭代异步生成器     # 在这之前task1, task2 这两个任务已经启动起来了, await只是确保等待他们完成await task1  # 等待任务1完成 确保任务完成await task2  # 等待任务2完成print("所有任务已完成")if __name__ == "__main__":asyncio.run(main())
  1. 在异步生成器内部进行并行
import asyncio
import timeasync def async_task(item):await asyncio.sleep(1)return f"处理结果:{item}"# 异步生成器:批量并行处理任务
async def parallel_async_generator(items, batch_size=2):# 按批次拆分任务for i in range(0, len(items), batch_size):batch = items[i:i+batch_size]# 并行执行批次内的任务(关键:asyncio.gather)batch_results = await asyncio.gather(*[async_task(item) for item in batch])for res in batch_results:yield resasync def test_main():start_time = time.time()items = [1, 2, 3, 4]  # 4个任务,批次大小2async for res in parallel_async_generator(items):print(res)print(f"总耗时:{time.time() - start_time:.2f}秒")if __name__ == '__main__': asyncio.run(test_main())

三、关系总结

特性迭代器生成器
是否是对象✅ 是✅ 是(生成器是迭代器的子类)
创建方式实现 __iter____next__;或 iter()yield 的函数 或 (… for …) 表达式
状态保存需手动维护状态自动保存函数执行上下文(栈帧)
编写复杂度较高(需定义类)极低(类似写普通函数)
是否可重复使用❌ 一次性❌ 一次性(除非重新调用生成器函数)

✅ 生成器是更轻量、更易用的迭代器实现方式
🎯 实际开发中,优先使用生成器(除非需要精细控制或实现复杂迭代逻辑)。


四、实用场景(结合你的兴趣)

  • WebSocket 数据流处理:可用 async for 遍历异步生成器(async def + yield),实现对实时消息流的惰性消费;
  • 大数据处理:读取大文件时用生成器逐行返回,避免内存爆炸;
  • 加密/解密流水线:构建生成器管道(如 decrypt → verify → parse),实现内存高效、可组合的数据处理。

4.1 读取文件

  1. 如果文件很大可以一行一行读取不会爆内存
def read_txt_line_by_line(file_path: str, encoding: str = "utf-8"):"""同步生成器:一行一行读取 TXT 文件:param file_path: TXT 文件路径(相对/绝对路径):param encoding: 文件编码(默认 utf-8,需根据实际文件调整,如 gbk):yield: 文件中的每一行(保留原始换行符 \n)"""# with 语句自动处理文件打开/关闭,避免资源泄露with open(file_path, "r", encoding=encoding) as f:# 循环读取每一行(文件对象本身是可迭代对象,逐行返回)for line in f:yield line  # 暂停并返回当前行,下次迭代从下一行继续if __name__ == '__main__': # 读取文件(替换为你的 TXT 文件路径), 确保你这个路径存在file_path = "test.txt"# 方式1:for 循环迭代(推荐,自动处理迭代终止)for line_num, line in enumerate(read_txt_line_by_line(file_path), start=1):print(f"第 {line_num} 行:{line}", end="")  # end="" 避免重复打印换行符
http://www.dtcms.com/a/602125.html

相关文章:

  • 编译型语言的两大步骤 | 深入理解编译过程与优化技术
  • (三)分支与合并 - git rebase 命令的使用
  • K8S上高可用SeaTunnel 集群部署
  • wdcp 默认网站中学网站建设方案 分校区
  • 网站营销站点有你想网页设计师个人简历参考范文
  • Windows 使用 docker 搭建 gitea
  • 多维决策系统的工程化实践:从评估框架到智能筛选引擎
  • 二十八、STM32的USART (介绍)
  • 双滦区seo整站排名seo在网站制作
  • 关于网站维护的书籍建设网站的技术性背景
  • 现代CPU性能分析与优化
  • 悬浮提词器免费版哪个好用?功能测评与实用应用场景
  • 使用OpenGL实现Gouraud材质
  • 2025年数据中心不间断电源(UPS)市场报告:趋势、挑战与投资战略全景分析
  • 网站建设开标书哪家公司
  • 【前端面试】CSS篇
  • 第六章,主从服务器
  • 16.udp_socket(三)
  • 【Git Merge branch】Git 合并提交(Merge Commit)的成因与清理:从本地修复到安全重写历史
  • 视觉学习篇——理清机器学习:分类、流程与技术家族的关系
  • 个人 网站备案 幕布wordpress黑群
  • 机器学习日报17
  • 沛县网站建设wordpress 标签 标题
  • 数字孪生IOC:让数据中心运维从“被动响应”到“主动预警”的智能革命
  • 长春作网站建设的公司wordpress上传到服务器发布
  • 炭黑仪:高精度材料分析的关键工具
  • C++条件判断与循环(一)(算法竞赛)
  • 电商网站维护网络销售是什么样的工作
  • 怎么给网站添加图标网页浏览器cookie
  • 贵州安顺建设主管部门网站信息可视化网站