1. 为什么需要自定义迭代器
在Python中,迭代器是一个可以记住遍历位置的对象。它从集合的第一个元素开始访问,直到所有元素被访问完结束。内置的列表、元组、字符串等序列类型都实现了迭代器协议,但有时我们需要更灵活的控制遍历过程。
自定义迭代器的典型场景包括:
- 处理非序列数据结构(如树形结构、图结构)
- 实现特殊的遍历顺序(如广度优先、深度优先)
- 对原始数据进行过滤或转换后再迭代
- 处理超大数据集时实现惰性计算
提示:Python的迭代器协议基于两个特殊方法:
__iter__()和__next__()。前者返回迭代器对象本身,后者返回下一个元素。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 迭代器协议实现详解
2.1 基础实现模板
下面是一个最简单的自定义迭代器实现示例:
python复制class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
这个实现有几个关键点需要注意:
__iter__方法必须返回迭代器对象本身__next__方法需要处理遍历结束的情况(抛出StopIteration)- 迭代器是有状态的,需要维护当前遍历位置
2.2 生成器方式的简化实现
Python提供了更简洁的实现方式——生成器函数:
python复制def my_generator(data):
for item in data:
yield item * 2 # 可以在迭代时进行转换
生成器会自动实现迭代器协议,代码更简洁但功能同样强大。在性能方面,生成器通常比类实现的迭代器更高效。
3. 实际应用案例:文件分块读取器
处理大文件时,一次性读取全部内容可能导致内存不足。我们可以实现一个分块读取的迭代器:
python复制class ChunkReader:
def __init__(self, file_path, chunk_size=1024):
self.file = open(file_path, 'rb')
self.chunk_size = chunk_size
def __iter__(self):
return self
def __next__(self):
data = self.file.read(self.chunk_size)
if not data:
self.file.close()
raise StopIteration
return data
def __del__(self):
if not self.file.closed:
self.file.close()
这个迭代器的特点:
- 每次只读取指定大小的数据块
- 自动处理文件关闭
- 可以像普通迭代器一样使用:
for chunk in ChunkReader('bigfile.bin'):
4. 高级迭代器模式
4.1 过滤迭代器
我们可以创建一个只返回满足条件的元素的迭代器:
python复制class FilterIterator:
def __init__(self, data, predicate):
self.data = data
self.predicate = predicate
self.index = 0
def __iter__(self):
return self
def __next__(self):
while self.index < len(self.data):
value = self.data[self.index]
self.index += 1
if self.predicate(value):
return value
raise StopIteration
使用示例:
python复制even_numbers = FilterIterator(range(10), lambda x: x % 2 == 0)
list(even_numbers) # [0, 2, 4, 6, 8]
4.2 组合迭代器
多个迭代器可以组合起来实现更复杂的功能:
python复制class ChainIterator:
def __init__(self, *iterables):
self.iterables = iterables
self.current_iter = iter(iterables[0])
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
return next(self.current_iter)
except StopIteration:
self.index += 1
if self.index >= len(self.iterables):
raise
self.current_iter = iter(self.iterables[self.index])
return next(self.current_iter)
这个迭代器可以依次遍历多个可迭代对象,类似于itertools.chain的功能。
5. 性能优化与注意事项
5.1 迭代器 vs 列表
虽然迭代器更节省内存,但在某些情况下性能可能不如列表:
- 多次遍历同一数据时,列表更高效
- 随机访问元素时,列表的O(1)访问优于迭代器的顺序访问
5.2 资源清理
迭代器经常涉及资源管理(如文件、网络连接)。确保实现__del__或上下文管理器来正确释放资源:
python复制class ResourceIterator:
def __init__(self, resource):
self.resource = resource
def __iter__(self):
return self
def __next__(self):
# 迭代逻辑
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.resource.close()
5.3 无限迭代器
有些迭代器可能永远不会触发StopIteration(如计数器)。使用时需要明确终止条件:
python复制from itertools import count
# 无限计数器
for i in count(start=0, step=1):
if i > 100: # 必须手动终止
break
print(i)
在实际项目中,我经常使用自定义迭代器来处理数据库查询结果、日志文件分析和网络数据流。一个实用的技巧是为迭代器添加日志记录功能,方便调试复杂的迭代逻辑。例如,可以在__next__方法中添加调试输出,记录每次迭代返回的值和内部状态变化。
