一、迭代器和生成器的基本概念

1. 迭代器的定义和工作原理

(1)迭代器的概念

迭代器(Iterator) 是 Python 中一种支持逐个访问元素的对象,它遵循 迭代器协议(Iterator Protocol),即实现了两个特殊方法:

  • __iter__():返回迭代器对象本身。
  • __next__():返回容器中的下一个元素;当没有更多元素时,抛出 StopIteration 异常。

迭代器提供了一种统一的方式来遍历各种可迭代对象(如列表、元组、字典、集合、文件等),而无需关心其内部结构。它实现了“用同一种方式遍历不同数据结构”的设计思想。

注意:range() 并不是一个迭代器,而是一个 可迭代对象(iterable)。调用 iter(range(5)) 才会得到一个迭代器。

(2)迭代器的特点
  1. 单向遍历:只能向前移动,不能回退或重置(除非重新创建)。
  2. 状态保持:迭代器自身维护当前遍历位置的状态。
  3. 惰性求值:许多迭代器采用惰性计算策略,按需生成数据,节省内存。
  4. 一次性使用:一旦遍历完成(触发 StopIteration),该迭代器通常无法再次使用(除非是特殊设计的可重置迭代器)。
(3)迭代器的使用方式
  • 使用 for 循环自动调用 __iter__()__next__()
  • 手动使用 next(iterator) 获取下一个元素
my_list = [1, 2, 3]
it = iter(my_list)
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# print(next(it))  # StopIteration
(4)迭代器的优势
  • 内存效率高:不一次性加载所有数据到内存。
  • 适用于大数据流:如读取大文件、网络流、传感器数据等。
  • 统一接口:为不同数据结构提供一致的遍历方式。

2. 生成器的定义和特点

生成器(Generator) 是一种特殊的迭代器,由生成器函数或生成器表达式创建。它自动实现了 __iter__()__next__() 方法,并能“记住”函数执行的状态。

(1)生成器的核心机制:yield
  • yield 关键字使函数暂停并返回一个值,下次调用 next() 时从暂停处继续执行。
  • return 不同,yield 不终止函数,而是“挂起”函数状态。
def count_up_to(n):i = 1while i <= n:yield ii += 1gen = count_up_to(3)
print(list(gen))  # [1, 2, 3]
(2)生成器的特点
  1. 自动实现迭代器协议:无需手动编写 __iter____next__
  2. 惰性计算:按需生成值,极大节省内存。
  3. 状态保存:函数局部变量在 yield 后仍保留。
  4. 简洁语法:代码更清晰,易于编写复杂迭代逻辑。

3. 迭代器与生成器的区别与联系

特性迭代器生成器
创建方式实现 __iter____next__使用 yield 函数 或 (expr) 表达式
编写复杂度较高,需手动管理状态简单,函数式风格
内存占用通常较低极低(函数栈 + 局部变量)
可重用性一般不可重用一般不可重用
是否为迭代器是(生成器是迭代器的子集)
惰性计算支持支持
调试难度相对容易状态隐式,调试略难

联系
所有生成器都是迭代器,但并非所有迭代器都是生成器。
生成器是对迭代器的高级封装,简化了迭代器的创建过程。


二、迭代器的实现和使用

1. 使用 iter()next() 手动操作

data = [10, 20, 30]
it = iter(data)
while True:try:value = next(it)print(value)except StopIteration:break

2. 自定义迭代器类

class CountDown:def __init__(self, start):self.start = startdef __iter__(self):return selfdef __next__(self):if self.start <= 0:raise StopIterationself.start -= 1return self.start + 1for n in CountDown(3):print(n)  # 3, 2, 1

3. 内置迭代工具的使用

Python 提供了丰富的内置迭代工具,位于 itertools 模块中:

  • enumerate(iterable):返回索引和值
  • zip(*iterables):并行遍历多个序列
  • itertools.count():无限计数器
  • itertools.cycle():循环遍历
  • itertools.chain():连接多个迭代器
from itertools import countcounter = count(1, 2)  # 1, 3, 5, ...
print(next(counter))  # 1
print(next(counter))  # 3

三、生成器的实现和使用

1. 生成器函数与 yield

def fibonacci():a, b = 0, 1while True:yield aa, b = b, a + bfib = fibonacci()
print([next(fib) for _ in range(10)])  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

2. 生成器表达式

语法类似于列表推导式,但使用 () 而非 [],返回生成器对象。

gen = (x**2 for x in range(5))
print(list(gen))  # [0, 1, 4, 9, 16]

优点:内存占用极小,适合大数据集处理。

3. 惰性计算特性

生成器只在需要时才计算下一个值,非常适合处理以下场景:

  • 大文件逐行读取
  • 数据流处理
  • 无限序列生成
def read_large_file(file_path):with open(file_path, 'r') as f:for line in f:yield line.strip()

四、实际应用场景

1. 处理大数据集时的内存优化

使用生成器避免将整个数据集加载到内存中:

#  危险:可能耗尽内存
lines = [line.strip() for line in open('huge_file.txt')]#  安全:逐行处理
def process_lines(filename):with open(filename) as f:for line in f:yield clean(line)for line in process_lines('huge_file.txt'):print(line)

2. 实现无限序列

def natural_numbers():n = 1while True:yield nn += 1nums = natural_numbers()
print([next(nums) for _ in range(5)])  # [1, 2, 3, 4, 5]

3. 协程与异步编程中的应用

生成器曾是 Python 协程的基础(@asyncio.coroutine + yield from),虽然后来被 async/await 取代,但理解生成器对掌握异步编程仍有帮助。

def echo():while True:received = yieldprint(f"Received: {received}")e = echo()
next(e)  # 启动生成器
e.send("Hello")  # Received: Hello

五、性能对比与注意事项

1. 性能对比

场景推荐方式原因
小数据、需多次遍历列表支持索引、可重复使用
大数据、单次遍历生成器内存友好
复杂状态控制自定义迭代器更灵活的状态管理
快速构建简单迭代生成器表达式语法简洁

2. 何时选择迭代器或生成器?

  • 选择生成器:逻辑清晰、函数式风格、一次性遍历、内存敏感。
  • 选择自定义迭代器:需要复杂状态管理、支持重置、多次遍历、面向对象设计。

3. 常见错误与调试技巧

  • 错误1:重复使用已耗尽的生成器
gen = (x for x in range(3))
print(list(gen))  # [0, 1, 2]
print(list(gen))  # [] —— 已耗尽!

解决方案:重新创建生成器或转为列表(牺牲内存)。

  • 错误2:忘记启动协程(使用 send 前未调用 next
gen = echo()
# gen.send("Hi")  # TypeError: can't send non-None value to a just-started generator
next(gen)  # 或 gen.send(None)
gen.send("Hi")
  • 调试建议:
  • 使用 itertools.tee() 复制迭代器用于调试(注意内存开销)
  • 将生成器转为列表进行测试(仅限小数据)

六、进阶话题

1. 生成器的 sendthrowclose 方法

  • send(value):向生成器发送值,作为 yield 表达式的返回值
  • throw(exc):在生成器内引发异常
  • close():关闭生成器,触发 GeneratorExit
def accumulator():total = 0while True:value = yield totalif value is not None:total += valueacc = accumulator()
print(next(acc))      # 0
print(acc.send(10))   # 10
print(acc.send(5))    # 15
acc.close()

2. 使用 yield from 简化嵌套生成器

yield from 可以将子生成器的值直接“委托”给外层生成器。

def sub_generator():yield "a"yield "b"def main_generator():yield 1yield from sub_generator()yield 2list(main_generator())  # [1, 'a', 'b', 2]

3. 结合 asyncio 实现异步生成器

Python 3.6+ 支持异步生成器,可用于异步数据流处理。

import asyncioasync def async_counter():for i in range(3):await asyncio.sleep(1)yield iasync def main():async for num in async_counter():print(num)# asyncio.run(main())

七、总结

1. 核心优势

  • 内存效率:惰性计算避免一次性加载大量数据。
  • 代码简洁:生成器让复杂迭代逻辑变得清晰。
  • 统一接口:迭代器协议使遍历操作标准化。
  • 扩展性强:支持无限序列、协程、异步等高级模式。

2. 实际开发中的推荐实践

  • 优先使用生成器处理大数据或流式数据。
  • 使用生成器表达式替代列表推导式(当只需遍历一次时)。
  • 避免对生成器做多次遍历,必要时缓存结果。
  • 在需要复杂状态管理时,考虑自定义迭代器类。
  • 善用 itertools 模块提高开发效率。

结语
掌握迭代器与生成器是成为 Python 高级开发者的重要一步。它们不仅是语言特性,更是一种编程思维——按需计算、延迟执行、资源节约。合理运用,可显著提升程序性能与可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/94664.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94664.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/94664.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 发送 HTTP POST请求教程

Java 发送 HTTP POST 请求的方法使用 HttpURLConnection&#xff08;原生 Java 支持&#xff09; 创建一个 HttpURLConnection 对象&#xff0c;设置请求方法为 POST&#xff0c;并写入请求体数据。以下是一个简单示例&#xff1a;import java.io.OutputStream; import java.ne…

计算机英语详细总结

计算机英语作为信息技术领域的专用语言&#xff0c;融合了专业术语、缩写、行业表达及技术文档规范&#xff0c;是学习编程、从事 IT 工作的核心工具。以下从核心分类、应用场景、学习方法三方面详细梳理&#xff1a;一、核心术语分类与高频词汇1. 编程语言与语法基础基础概念&…

「日拱一码」045 机器学习-因果发现算法

目录 基于约束的方法 (Constraint-based) 基于评分的方法 (Score-based) 基于函数因果模型的方法 (Functional Causal Models) 基于梯度的方法 (Gradient-based) 因果发现是机器学习中一个重要的研究方向&#xff0c;它旨在从观测数据中推断变量之间的因果关系 基于约束的…

S7-1200 串行通信介绍

S7-1200 串行通信S7-1200支持的串行通讯方式点对点&#xff08;PtP&#xff09;通信Modbus 主从通信USS 通信名称CM 1241 RS232CM 1241 RS422/485CB 1241 RS485订货号6ES7241-1AH32-0XB06ES7241-1CH32-0XB06ES7241-1CH30-1XB0通讯口类型RS232RS422/RS485RS485波特率(bps)300 ;6…

达梦包含OR条件的SQL特定优化----INJECT-HINT优化方法

Time:2025/08/07Author:skatexg应用迭代发版须执行如下动作 1、按目标需求全面压力测试&#xff0c;优化潜在慢SQL或设置特殊优化参数(如&#xff1a;OPTIMIZER_OR_NBEXP) 2、达梦数据库有数据导入&#xff0c;必须收集统计信息达梦使用SF_INJECT_HINT系统函数对指定SQL增加HIN…

JSqlParser学习笔记 快速使用JSqlParser

文章目录前言本章节源码官方文档信息认识JSqlParserHow it works? 它是如何工作的&#xff1f;知识点关于statement实际应用场景引入依赖Parser 解析SQL解析sql语句解析sql区分sql类型分析增删改查语句查询语句认识PlainSelect示范新增语句了解Insert常用方法示范更新语句删除…

Godot ------ 中级人物血条制作01

Godot ------ 中级人物血条制作 引言 正文 传统血条制作 方格血条制作 传奇,暗黑破环神类血条显示 引言 在此之前,我们分四篇介绍了 Godot 中人物血条的制作,但是我们用到的都是比较基础的节点 ProgressBar,本文我们将介绍另外一种相对高级的节点 TextureProgressBar。 正…

《WebPages 类:构建高效网页的基石》

《WebPages 类&#xff1a;构建高效网页的基石》 引言 在互联网高速发展的今天&#xff0c;网页作为信息传递和交互的重要载体&#xff0c;其重要性不言而喻。而一个高效、美观、易用的网页&#xff0c;往往离不开一个优秀的网页类的设计。本文将深入探讨WebPages类的概念、特点…

直播预告|鸿蒙生态下的 Flutter 开发实战

《开发者 面对面》坚果派特辑直播&#xff08;二&#xff09;来了&#xff01;在鸿蒙系统日益完善的今天&#xff0c;Flutter 开发者将迎来哪些新机遇&#xff1f;在 HarmonyOS 上开发 Flutter&#xff0c;如何实现高效适配与生态融合&#xff1f;本期「开发者面对面」坚果派特…

web前端结合Microsoft Office Online 在线预览,vue实现(PPT、Word、Excel、PDF等)

web前端结合Microsoft Office Online 在线预览&#xff0c;vue实现&#xff08;PPT、Word、Excel、PDF等&#xff09; 什么是 Microsoft Office Online 预览服务 Microsoft Office Online 预览服务是由微软提供的免费在线文档预览工具&#xff0c;通过简单的 URL 参数配置&am…

安卓手机用久了会出现卡顿,为什么?

安卓手机用久了出现卡顿&#xff0c;主要与内存不足、系统机制特性、硬件老化、软件冲突与冗余、使用习惯不当五大核心因素相关。以下是具体原因及针对性解决方案&#xff1a;一、卡顿核心原因分析内存不足运行内存&#xff08;RAM&#xff09;被占用&#xff1a;安卓应用默认在…

以 Eland 玩转 Elasticsearch 8.12 Learning-to-Rank

1 为什么要在 Elasticsearch 上做 LTR&#xff1f; 适用版本&#xff1a; Elasticsearch ≥ 8.12.0 前置条件&#xff1a; 需拥有包含 “Serverless LTR” 的订阅等级&#xff08;详见官方订阅矩阵&#xff09; 技术栈&#xff1a; Elasticsearch Python Eland XGBoost / Li…

OpenCV入门:图像处理基础教程

OpenCV简介 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习库。它包含超过2500种优化算法&#xff0c;涵盖图像处理、物体识别、人脸检测、3D重建、视频分析等任务。 核心功能 图像处理&#xff1a;滤波、边缘检测、几…

影响内容传播速度的因素有哪些?

内容的传播速度是我们在衡量营销效果时的重要指标。传播速度越快&#xff0c;越能帮助品牌迅速覆盖目标受众&#xff0c;在短时间内提升影响力。影响内容传播速度的方式来自多个方面&#xff0c;下面就让我们一同来了解下这其中的因素。一、观点价值观点是否具有价值&#xff0…

css动态样式

使用scss通过变量设置css动态样式<template><div><!-- 方式一 --><p v-for"(item, index) in dataList" :key"index" :style"{--color: item.color}" >{{item.name}}</p><!-- 方式二 --><p v-for"(…

开源流媒体服务器ZLMediaKit 的Java Api实现的Java版ZLMediaKit流媒体服务器-二开视频对话

安全性&#xff1a;使用了WSS&#xff08;WebSocket Secure&#xff09;协议确保通信安全 兼容性&#xff1a;支持现代浏览器的WebRTC功能 信令机制&#xff1a;通过WebSocket进行信令交换&#xff0c;确保连接建立 媒体传输&#xff1a;使用STUN服务器进行NAT穿透&#xff0c;…

mariadb10.3.35备份脚本

一、创建备份用户[(none)]> create user buserlocalhost identified by tmrQ;[(none)]> GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO buserlocalhost;[(none)]> flush privileges;二、脚本# cat mysql_bask.sh #!/bin/bash # MariaDB 10.3.35…

W3D引擎游戏开发----从入门到精通【22】

配置完成基本DT物体项后&#xff0c;在这个DT物体项中开始添加这个玩家的动画信息&#xff0c;如下所示。UseAnim设置是否使用动画功能&#xff0c;这里开启。AnimTypeN设置总共的动画类型数&#xff0c;当前只有一个待机动画&#xff0c;因此设置为1。AnimType1FrameN设置1号动…

在我国申请注册的商标在国外可以用不!

近日一个网友找到普推知产商标老杨&#xff0c;问在我国申请注册商标在新加坡和欧盟可以用不&#xff0c;当然用不成&#xff0c;根据商标法的地域性原则&#xff0c;商标权保护限于注册地&#xff0c;驰名商标享有部分跨国保护&#xff0c;但是这个要有所在国相关法律证据。如…

在开发板上画出一个2048棋盘的矩阵

#include “head.h"int* p lcd NULL; //显示屏内存映射的起始地址int g lcd width; //LCD显示屏的宽度int g lcd high ; //LCD显示屏的高度int g lcd bpp; //每个像素点所占的比特位//int x:屏的X轴&#xff08;宽度、列&#xff09;坐标//int y:屏幕y轴&#xff08;高度、…