AI_Python基础-6.迭代器与生成器
·
Python 迭代器与生成器
标签: #Python #迭代器 #生成器 #yield #延迟计算
学习周期:1 天 | 核心目标:理解迭代协议,掌握生成器实现延迟计算,对比列表推导式与生成器表达式的内存差异
3.2 迭代器与生成器
迭代器与生成器是 Python 中高效处理序列数据的核心工具,核心优势是 延迟计算(惰性求值) —— 不一次性生成所有数据,而是按需生成,大幅节省内存(尤其适合处理海量数据)。
3.2.1 可迭代对象(__iter__)与迭代器(__next__)
核心概念对比
| 类型 | 核心特征 | 关键方法 | 示例 |
|---|---|---|---|
| 可迭代对象 | 能被 for 循环遍历,可生成迭代器 |
__iter__():返回迭代器 |
list、str、tuple、dict、set |
| 迭代器 | 可逐个返回元素,可记录遍历位置,只能遍历一次 | __next__():返回下一个元素;__iter__():返回自身 |
iter(list)、文件对象、生成器对象 |
判断可迭代对象和迭代器
from collections.abc import Iterable, Iterator
lst = [1, 2, 3]
print(isinstance(lst, Iterable)) # True(可迭代)
print(isinstance(lst, Iterator)) # False(不是迭代器)
it = iter(lst) # 获取迭代器
print(isinstance(it, Iterator)) # True
手动使用迭代器
lst = [1, 2, 3]
it = iter(lst) # 获取迭代器
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
# print(next(it)) # StopIteration 异常
for 循环的工作原理
# for 循环等价于:
it = iter(可迭代对象)
while True:
try:
value = next(it)
# 执行循环体
except StopIteration:
break
自定义迭代器
class MyIterator:
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
temp = self.current
self.current += 1
return temp
my_iter = MyIterator(1, 3)
for num in my_iter:
print(num) # 1, 2, 3
# 再次遍历(迭代器已耗尽,无输出)
for num in my_iter:
print(num)
易错点说明
- 可迭代对象 ≠ 迭代器:可迭代对象需要通过
iter()转换为迭代器才能手动遍历。 - 迭代器只能遍历一次:遍历结束后指针停在最后,无法重置,需重新创建迭代器。
for循环的底层逻辑:先调用iter(可迭代对象)生成迭代器,再循环调用next(),直到捕获StopIteration异常,自动终止循环。
3.2.2 生成器函数(yield)—— 延迟计算,节省内存
生成器是一种特殊的迭代器,使用 yield 关键字定义。生成器函数在每次调用 next() 时执行到 yield 暂停并返回一个值,下次调用从暂停处继续。
核心特性
- 延迟计算:只在需要时生成值,节省内存。
- 状态保持:函数内的局部变量在每次
yield之间保持。 - 无限序列:可以表示无限大的序列(如斐波那契数列)。
基本用法
def my_generator(start, end):
current = start
while current <= end:
yield current
current += 1
gen = my_generator(1, 3) # 创建生成器对象,函数体不会立即执行
print(type(gen)) # <class 'generator'>
print(isinstance(gen, Iterator)) # True
# 手动遍历
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# print(next(gen)) # StopIteration
# for 循环遍历(推荐)
for num in my_generator(1, 3):
print(num) # 1, 2, 3
生成器实现斐波那契数列(节省内存)
def fibonacci(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
for num in fibonacci(100):
print(num, end=" ") # 0 1 1 2 3 5 8 13 21 34 55 89
生成器的进阶方法(send、close)
def echo():
while True:
received = yield
print(f"收到:{received}")
gen = echo()
next(gen) # 预激生成器,执行到第一个 yield
gen.send("Hello") # 收到:Hello
gen.send("World") # 收到:World
gen.close() # 关闭生成器
应用场景
- 处理海量数据(如读取超大文件、生成百万级随机数),避免内存溢出。
- 惰性计算场景:批量处理数据,不需要一次性获取所有结果。
- 替代列表推导式:当数据量较大时,用生成器替代列表推导式。
3.2.3 生成器表达式
生成器表达式类似于列表推导式,但使用圆括号 () 而不是方括号 []。它返回一个生成器对象,而不是一次性创建列表,适合处理大量数据。
语法
(expression for item in iterable if condition)
示例与对比
# 列表推导式:立即生成所有值,占用内存
squares_list = [x**2 for x in range(10)]
print(squares_list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 生成器表达式:延迟计算,不占内存
squares_gen = (x**2 for x in range(10))
print(squares_gen) # <generator object <genexpr> at 0x...>
for val in squares_gen:
print(val, end=" ") # 0 1 4 9 16 25 36 49 64 81
# 一次性转换为列表(失去生成器的优势)
squares_list2 = list(x**2 for x in range(10))
内存对比
import sys
# 列表推导式:立即分配内存
list_comp = [x for x in range(1000000)]
print(sys.getsizeof(list_comp)) # 约 8 MB
# 生成器表达式:几乎不占内存
gen_exp = (x for x in range(1000000))
print(sys.getsizeof(gen_exp)) # 约 104 字节
与高阶函数配合
# 计算 1 到 1e6 的平方和(无需创建巨大列表)
total = sum(x**2 for x in range(1, 1000001))
print(total)
# 找出 1 到 1e6 中能被 7 整除的最大数
max_val = max(x for x in range(1, 1000001) if x % 7 == 0)
print(max_val)
实战场景:逐行读取大文件
def read_large_file(file_path):
return (line.strip() for line in open(file_path, "r", encoding="utf-8"))
# 使用:按需读取,内存占用极低
for line in read_large_file("large_file.txt"):
print(line) # 逐行处理
易错点说明
- 生成器表达式的圆括号不能省略,否则会变成普通表达式。
- 生成器表达式也是“一次性的”,遍历结束后无法重复使用,需重新定义。
- 数据量小且需要多次访问时用列表推导式;数据量大且只需遍历一次时用生成器表达式。
3.2.4 迭代器、生成器与列表推导式的选择
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 数据量小,需要多次遍历 | 列表推导式 | 值已存储在内存中,访问快 |
| 数据量大,只需遍历一次 | 生成器表达式或生成器函数 | 节省内存,延迟计算 |
| 需要复杂逻辑控制 | 生成器函数(yield) |
可暂停、保持状态,代码清晰 |
| 需要向生成器发送数据 | 生成器函数 + send() |
双向通信 |
📚 学习资料(Obsidian 可直接收藏)
🎯 学习建议(1 天计划)
- 上午:理解可迭代对象与迭代器的区别,手动实现
__iter__和__next__,练习生成器函数(yield)。 - 下午:掌握生成器表达式,对比列表推导式的内存占用,完成实战练习(大文件读取、无限序列生成)。
✅ 核心要点总结
- 可迭代对象:实现了
__iter__(),返回迭代器。常见的有list、str、dict等。 - 迭代器:实现了
__iter__()和__next__(),只能遍历一次。for循环依赖迭代协议。 - 生成器函数:使用
yield的函数,调用时返回生成器对象(属于迭代器),支持延迟计算和状态保持。 - 生成器表达式:类似列表推导式但使用
(),返回生成器对象,适合大数据量处理。 - 内存优势:生成器和生成器表达式不一次性存储所有元素,处理大数据集时能显著降低内存占用。
- 一次性特点:生成器和迭代器都只能遍历一次,无法重置。
练习题(自测)
- 定义一个可迭代对象
Fibonacci,使用__iter__和__next__实现斐波那契数列的前n项。 - 编写生成器函数
read_large_file(file_path),逐行读取大文件(模拟),每次yield一行。 - 使用生成器表达式找出 1 到 100000 中所有能被 13 整除的数,并计算它们的和(不使用列表)。
- 实现一个无限生成器
cycle(iterable),无限循环返回可迭代对象中的元素(如cycle('AB')输出A B A B ...)。 - 写一个生成器
primes(),无限产生素数(使用埃拉托斯特尼筛法或试除法)。
建议在 Jupyter Notebook 或本地环境中运行,比较生成器和列表推导式的内存差异。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)