Python生成器与迭代器深度解析:内存高效的数据流处理编程模式

Python生成器与迭代器深度解析:内存高效的数据流处理编程模式

迭代器其实就像是一个智能的书签。你不需要把整本书都记在脑子里 只要知道当前读到哪一页就行了。

每次调用next()方法 就翻到下一页。简单粗暴。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 自定义迭代器实现
class NumberIterator:
def __init__(self, max_num):
self.max_num = max_num
self.current =0
def __iter__(self):
return self
def __next__(self):
if self.current <self.max_num:
self.current +=1
return self.current
else:
raise StopIteration
# 使用方式
numbers =NumberIterator(5)
for num in numbers:
print(num)# 输出 1 2 3 4 5

但是写起来真的很麻烦啊。

生成器就不一样了 简直是懒人福音。

yield关键字 函数就自动变成了生成器 不需要手动实现那些复杂的协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
def simple_generator(n):  
"""简单生成器示例"""
for i in range(n):
print(f"生成数字: {i}")
yield i # 关键就在这里
print(f"数字 {i} 已被消费")
# 创建生成器对象
gen = simple_generator(3)
# 逐个获取值
print(next(gen))
# 生成数字: 0, 返回 0, 数字 0 已被消费
print(next(gen))
# 生成数字: 1, 返回 1, 数字 1 已被消费

你会发现 每次调用next()函数都会从上次暂停的地方继续执行。这就是生成器的核心魅力。

暂停和恢复 就像视频播放器一样。

在实际项目中 我最常用生成器来处理大文件。

比如那个50GB的日志文件 用生成器的话 内存占用几乎可以忽略不计。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def read_large_file(file_path):  
"""大文件逐行读取生成器"""
with open(file_path,'r', encoding='utf-8')as file:
for line in file: # 可以在这里做一些预处理
cleaned_line = line.strip()
if cleaned_line:# 跳过空行
yield cleaned_line

def process_log_data(file_path):
"""处理日志数据的业务逻辑"""
error_count =0
for line in read_large_file(file_path):
if'ERROR'in line:
error_count +=1 # 这里可以做错误分析
print(f"发现错误: {line[:100]}")# 只显示前100字符
return error_count
# 使用方式# total_errors = process_log_data('huge_log.txt')

这样写的好处是什么呢 内存使用量始终保持在很低的水平 不管文件多大。

生成器表达式更是简洁到爆炸。

就像列表推导式的懒加载版本 用圆括号包起来就行了。

1
2
3
4
5
6
7
8
9
# 列表推导式 - 立即创建所有元素squares_list =[x**2for x in range(1000000)]# 占用大量内存
# 生成器表达式 - 按需生成squares_gen =(x**2for x in range(1000000))# 几乎不占内存
# 实际使用场景
def find_large_squares(limit):
"""找出大于某个值的平方数"""
squares =(x**2for x in range(10000))
return[sq for sq in squares if sq > limit]
result = find_large_squares(50000)
print(f"找到 {len(result)} 个符合条件的平方数")

当你需要处理大量数据但只关心其中一部分时 生成器表达式就是最佳选择。

节省内存又提升性能。

有个经常踩的坑需要提醒一下。

生成器只能迭代一次 用完就没了 就像一次性筷子。

1
2
3
4
5
6
7
8
9
10
def demo_generator():  
for i in range(3):
yield i
gen = demo_generator()
# 第一次迭代
list1 = list(gen)# [0, 1, 2]
# 第二次迭代
list2 = list(gen)# [] 空列表!
print(f"第一次: {list1}")
print(f"第二次: {list2}")

如果需要多次使用 要么重新创建生成器 要么把结果先存起来。

另外 生成器和协程的结合也很有意思 可以实现更复杂的异步数据处理流程。但那就是另一个话题了。

总的来说 掌握生成器和迭代器真的能让你的Python代码更加优雅高效。特别是在处理大数据集的时候 这些技巧能救你一命。

https://mp.weixin.qq.com/s/aS1aD5wfm8EYmfTzWbCdqA?scene=1