【Python】迭代器(Iterator)vs 生成器(Generator)
迭代器(Iterator) vs 生成器(Generator)
- 1.迭代器(Iterator)
- 1.1 是什么?
- 1.2 示例
- 1.3 适用场景
- 2.生成器(Generator)
- 2.1 是什么?
- 2.2 示例
- 2.3 适用场景
- 3.迭代器 vs 生成器
- 4.如何选择?
- 5.经典例子
- 5.1 读取大文件(生成器更优)
- 5.2 自定义树遍历(迭代器更优)
- 6.总结
1.迭代器(Iterator)
1.1 是什么?
- 迭代器是一个 可以逐个访问元素的对象,比如
list
、dict
、set
都可以通过iter()
转换成迭代器。 - 它必须实现
__iter__()
和__next__()
方法。 - 特点:
- 只能前进,不能后退。
- 遍历结束后,再调用
next()
会抛出StopIteration
错误。
1.2 示例
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
1.3 适用场景
- 大数据遍历(如逐行读取大文件,避免内存爆炸)。
- 自定义遍历逻辑(如树的深度优先遍历,就像《迭代器与生成器(一)》中的
DepthFirstIterator
)。
2.生成器(Generator)
2.1 是什么?
- 生成器是一种 特殊的迭代器,用
yield
关键字定义。 - 特点:
- 惰性计算(需要时才计算,节省内存)。
- 代码更简洁,不用手动实现
__iter__
和__next__
。 - 可以用
for
循环直接遍历。
2.2 示例
def count_up_to(n):i = 1while i <= n:yield i # 每次 next() 调用时返回 i,并暂停在这里i += 1gen = count_up_to(3) # 返回生成器对象print(next(gen)) # 输出 1
print(next(gen)) # 输出 2
print(next(gen)) # 输出 3
print(next(gen)) # 抛出 StopIteration# 也可以用 for 循环
for num in count_up_to(3):print(num) # 输出 1, 2, 3
2.3 适用场景
- 处理大数据流(如逐行读取日志文件)。
- 无限序列(如斐波那契数列)。
- 协程(Coroutine)(结合
yield
实现异步编程)。
3.迭代器 vs 生成器
特性 | 迭代器(Iterator) | 生成器(Generator) |
---|---|---|
定义方式 | 需要实现 __iter__ 和 __next__ | 用 yield 定义函数 |
内存占用 | 可能占用较大内存(如 list ) | 惰性计算,省内存 |
代码简洁度 | 较复杂(需手动实现) | 更简洁 |
适用场景 | 自定义遍历逻辑 | 惰性计算、无限序列、协程 |
4.如何选择?
- 用迭代器:
- 需要自定义遍历逻辑(如树、图的遍历)。
- 需要更底层的控制(如手动调用
next()
)。
- 用生成器:
- 需要 惰性计算(如处理大文件、无限序列)。
- 代码要更简洁(避免手动实现
__next__
)。
5.经典例子
5.1 读取大文件(生成器更优)
def read_large_file(file_path):with open(file_path, "r") as f:for line in f:yield line # 逐行读取,不占内存for line in read_large_file("huge_log.txt"):print(line)
✅ 生成器更合适,因为文件可能很大,直接 read()
会爆内存。
5.2 自定义树遍历(迭代器更优)
class Tree:def __init__(self, value):self.value = valueself.children = []def __iter__(self):return DepthFirstIterator(self) # 自定义迭代器
✅ 迭代器更合适,因为需要控制遍历顺序(如深度优先、广度优先)。
6.总结
- 迭代器:适合 自定义遍历逻辑(如树、图)。
- 生成器:适合 惰性计算(如大文件、无限序列)。
- 生成器是迭代器的“语法糖”,能用生成器的地方尽量用生成器,代码更简洁!
希望本文能让你搞懂迭代器和生成器!🚀