这篇文章将帮助你理解:
什么是迭代器(Iterator)?
它和我们常用的for 循环、列表有什么区别?
为什么说它在处理大数据或惰性求值时更有优势?
如何自己实现一个迭代器?
我们在写代码的时候,经常会遇到这样的需求:
“我要依次访问一组数据中的每一个元素。”
比如:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
这段代码看起来很自然。但你知道吗?其实背后有一个非常重要的机制在起作用——这就是我们今天要讲的主角:迭代器(Iterator)。
迭代器是一个对象,它可以记住遍历的位置,并能一步步返回下一个元素。
你可以把它想象成一个“翻页器”:
每次调用 .next()
或 next()
,它就会给你下一页内容;
如果没有更多内容了,它就会抛出一个 StopIteration
异常。
名称 | 中文名 | 特点 |
---|---|---|
Iterable | 可迭代对象 | 能被 for 遍历的对象,如列表、字符串、字典等 |
Iterator | 迭代器 | 是一个实现了 .__iter__() 和 .__next__() 的对象 |
关键点:
所有迭代器都是可迭代对象,但不是所有可迭代对象都是迭代器。
举个例子:
nums = [1, 2, 3] # 列表是可迭代对象
it = iter(nums) # iter() 返回一个迭代器
我们来看一个手动使用迭代器的例子:
fruits = ["apple", "banana", "cherry"]
it = iter(fruits)
print(next(it)) # apple
print(next(it)) # banana
print(next(it)) # cherry
print(next(it)) # 抛出 StopIteration 异常
这就是迭代器的本质:
一次只返回一个元素;
记住当前位置;
数据用完后自动停止。
假设你要读取一个超大的日志文件,几GB大小。如果你一次性读入内存,电脑可能直接崩溃。
但如果使用迭代器,就可以一行一行地读取,而不是一次性加载全部内容。
with open("huge_log_file.log") as f:
for line in f: # f 是一个迭代器
process(line) # 逐行处理,不占内存
类比理解:就像看书一样,一页一页看,而不是把整本书拍到脸上。
有些数据你并不需要一开始就计算出来,而是按需生成。这在函数式编程中非常常见。
例如,我们可以用迭代器实现一个“无限序列”:
import itertools
counter = itertools.count(start=1, step=1) # 无限计数器for i in counter:
if i > 10:
break
print(i)
输出:
1
2
3
...
10
关键点:这个迭代器并不会真正存储所有数字,而是在你需要时才“生成”它们。
Python 允许我们通过定义类的方式,创建自己的迭代器。只需满足两个条件:
实现 __iter__()
方法;
实现 __next__()
方法。
class MyCounter:
def __init__(self, start=1, end=10):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current > self.end:
raise StopIteration
else:
value = self.current
self.current += 1
return value
# 使用自定义迭代器
counter = MyCounter() #注意,不能用counter = MyCounter(1,5),否则不会走自定义
for num in counter:
print(num)
输出:
1
2
3
4
5
✅ 总结:
自定义迭代器让你拥有对“遍历逻辑”的完全控制;
它非常适合用于封装复杂的遍历规则或数据流。
对比项 | 迭代器 | 生成器 |
---|---|---|
创建方式 | 类 + 实现 __iter__ 和 __next__ |
函数 + yield |
内存占用 | 更灵活 | 更简洁 |
适用场景 | 复杂控制逻辑 | 快速构建惰性序列 |
举个生成器的例子:
def my_generator():
yield 1
yield 2
yield 3
g = my_generator()
for x in g:
print(x)
输出:
1
2
3
生成器本质上也是一个迭代器,但它更简洁、更易用。
迭代器不是一个循环,而是一种“按需提供数据”的机制。
它让我们的程序更高效、更灵活,尤其适合处理大数据、流式数据或无限序列。
说法 | 正确理解 |
---|---|
所有 for 循环都用了迭代器? | ✅ 是的,因为 for 内部会调用 iter() |
列表是迭代器? | ❌ 不是,列表是可迭代对象,不是迭代器 |
迭代器只能用一次? | ✅ 是的,一旦遍历完成,必须重新获取一个新的迭代器 |
生成器不是迭代器? | ❌ 错,生成器是特殊的迭代器 |
如果你想进一步深入学习:
学习 itertools
标准库,掌握强大的迭代工具;
探索生成器表达式与列表推导式的区别;
了解协程(coroutine)与生成器的关系;
理解迭代器在异步编程(async/await)中的应用。
推荐阅读资源:
《流畅的 Python》(Luciano Ramalho)
《Python 编程:从入门到实践》
Python 官方文档(docs.python.org)
用迭代器读取大文件并统计词频
实现一个“网页爬虫”,逐页抓取数据并处理