1. 为什么需要理解迭代器?
在Python中,for循环是我们每天都会用到的结构,但很少有人真正思考它是如何工作的。当我第一次看到for item in my_list:这样的代码时,我以为Python只是简单地按索引顺序访问列表元素。直到有一天,我尝试用for循环遍历一个打开的文件对象,才发现事情没那么简单。
迭代器模式是Python中最重要的设计模式之一。它提供了一种统一的方式来遍历不同类型的数据结构——无论是列表、字典、文件,还是数据库查询结果。这种统一性让我们的代码更加灵活和可扩展。
关键理解:迭代器协议是Python中for循环能够工作的基础,也是生成器、异步编程等高级特性的基石。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 迭代器协议详解
2.1 迭代器协议的两大核心方法
Python的迭代器协议非常简单,只需要实现两个特殊方法:
python复制class MyIterator:
def __iter__(self):
return self
def __next__(self):
# 返回下一个值或抛出StopIteration
...
__iter__方法返回迭代器对象本身,而__next__方法负责返回序列中的下一个元素。当没有更多元素时,它必须抛出StopIteration异常。
2.2 内置类型的迭代器实现
让我们看看Python内置类型是如何实现迭代器的:
python复制# 列表的迭代器
my_list = [1, 2, 3]
list_iter = iter(my_list) # 调用my_list.__iter__()
print(next(list_iter)) # 1
print(next(list_iter)) # 2
print(next(list_iter)) # 3
print(next(list_iter)) # 抛出StopIteration
字典的迭代器稍有不同,它可以迭代键、值或键值对:
python复制my_dict = {'a': 1, 'b': 2}
for key in my_dict: # 默认迭代键
print(key)
for value in my_dict.values():
print(value)
for key, value in my_dict.items():
print(key, value)
2.3 文件对象的迭代器
文件对象也是一个很好的迭代器例子:
python复制with open('data.txt') as f:
for line in f: # 文件对象本身就是迭代器
print(line)
这种实现方式非常高效,因为它不会一次性将整个文件加载到内存中,而是按需读取。
3. 自定义迭代器实战
3.1 实现一个简单的计数器迭代器
让我们创建一个从1数到n的迭代器:
python复制class Counter:
def __init__(self, limit):
self.limit = limit
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current >= self.limit:
raise StopIteration
self.current += 1
return self.current
# 使用示例
for num in Counter(5):
print(num) # 输出1到5
3.2 更实用的斐波那契数列迭代器
下面是一个更有实用价值的例子——生成斐波那契数列:
python复制class Fibonacci:
def __init__(self, max_count):
self.max_count = max_count
self.count = 0
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
if self.count >= self.max_count:
raise StopIteration
self.count += 1
result = self.a
self.a, self.b = self.b, self.a + self.b
return result
# 生成前10个斐波那契数
for num in Fibonacci(10):
print(num)
3.3 带过滤功能的迭代器
我们还可以创建带过滤功能的迭代器:
python复制class FilterIterator:
def __init__(self, iterable, filter_func):
self.iterator = iter(iterable)
self.filter_func = filter_func
def __iter__(self):
return self
def __next__(self):
while True:
item = next(self.iterator)
if self.filter_func(item):
return item
# 只输出偶数
for num in FilterIterator(range(10), lambda x: x % 2 == 0):
print(num) # 0, 2, 4, 6, 8
4. 迭代器的高级应用
4.1 惰性求值与内存效率
迭代器最大的优势之一是惰性求值(Lazy Evaluation)。考虑这个例子:
python复制def big_list():
result = []
for i in range(1000000):
result.append(i)
return result
# 传统方式会占用大量内存
numbers = big_list()
# 使用生成器表达式(一种迭代器)
numbers_gen = (i for i in range(1000000))
生成器表达式不会立即创建包含100万个元素的列表,而是按需生成每个元素,大大节省了内存。
4.2 itertools模块的强大工具
Python的itertools模块提供了许多有用的迭代器工具:
python复制import itertools
# 无限计数器
counter = itertools.count(start=10, step=2)
print(next(counter)) # 10
print(next(counter)) # 12
# 循环迭代
cycler = itertools.cycle(['a', 'b', 'c'])
print(next(cycler)) # 'a'
print(next(cycler)) # 'b'
print(next(cycler)) # 'c'
print(next(cycler)) # 'a' 又回到开头
# 排列组合
perms = itertools.permutations('ABC', 2)
for p in perms:
print(p) # AB, AC, BA, BC, CA, CB
4.3 链式迭代器处理
我们可以将多个迭代器操作链式组合:
python复制import itertools
# 创建数据处理管道
numbers = range(10)
processed = (
n * 2 # 第一步:乘以2
for n in numbers
if n % 2 == 0 # 第二步:过滤偶数
)
for num in processed:
print(num) # 0, 4, 8, 12, 16
这种方式既高效又易于理解,是函数式编程风格的体现。
5. 迭代器与生成器的关系
5.1 生成器是迭代器的语法糖
生成器函数是创建迭代器的便捷方式:
python复制def fibonacci(max_count):
a, b = 0, 1
count = 0
while count < max_count:
yield a
a, b = b, a + b
count += 1
# 使用方式与迭代器完全相同
for num in fibonacci(10):
print(num)
yield关键字会暂停函数执行并返回一个值,下次迭代时从暂停处继续执行。
5.2 生成器表达式
类似于列表推导式,但返回的是迭代器:
python复制# 列表推导式 - 立即计算
squares_list = [x**2 for x in range(10)]
# 生成器表达式 - 惰性计算
squares_gen = (x**2 for x in range(10))
print(sum(squares_gen)) # 285
5.3 协程与双向通信
生成器进阶用法支持双向通信:
python复制def accumulator():
total = 0
while True:
value = yield total
if value is None:
break
total += value
acc = accumulator()
next(acc) # 启动生成器
print(acc.send(10)) # 10
print(acc.send(20)) # 30
print(acc.send(5)) # 35
这种模式是Python协程的基础,也是异步编程的核心。
6. 常见陷阱与最佳实践
6.1 迭代器只能消费一次
一个常见的误区是认为可以多次遍历同一个迭代器:
python复制numbers = (x for x in range(5)) # 生成器表达式
print(sum(numbers)) # 10
print(sum(numbers)) # 0 - 迭代器已耗尽
解决方案是如果需要多次遍历,可以转换为列表或重新创建迭代器。
6.2 无限迭代器
某些迭代器可能永远不会停止:
python复制from itertools import count
for n in count(): # 无限计数
print(n)
if n > 10:
break
使用时要确保有明确的终止条件。
6.3 迭代过程中修改容器
在迭代过程中修改容器可能导致意外行为:
python复制my_list = [1, 2, 3, 4]
for item in my_list:
if item == 2:
my_list.remove(1) # 危险!
print(item)
安全做法是迭代副本或在修改前收集需要修改的项目。
6.4 性能优化技巧
对于大型数据集,迭代器可以显著提高性能:
python复制# 低效方式 - 两次遍历
sum_of_squares = sum([x**2 for x in range(1000000)])
# 高效方式 - 一次遍历
sum_of_squares = sum(x**2 for x in range(1000000))
生成器表达式避免了创建中间列表,节省内存和时间。
7. 实际项目中的应用案例
7.1 分块读取大文件
处理GB级日志文件时,迭代器模式非常有用:
python复制def read_in_chunks(file_object, chunk_size=1024):
while True:
data = file_object.read(chunk_size)
if not data:
break
yield data
with open('huge.log') as f:
for chunk in read_in_chunks(f):
process(chunk) # 处理每个块
7.2 数据库查询结果流式处理
大多数数据库API都使用迭代器返回查询结果:
python复制import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM large_table')
# 不会一次性加载所有结果
for row in cursor:
process_row(row)
7.3 实现观察者模式
迭代器可用于实现简单的发布-订阅系统:
python复制class EventStream:
def __init__(self):
self._subscribers = []
def subscribe(self):
queue = []
self._subscribers.append(queue.append)
return iter(queue)
def publish(self, event):
for subscriber in self._subscribers:
subscriber(event)
stream = EventStream()
events = stream.subscribe()
stream.publish('event1')
stream.publish('event2')
for event in events:
print(event) # 输出event1, event2
7.4 实现状态机
迭代器非常适合表示状态机:
python复制def traffic_light():
while True:
yield 'green'
yield 'yellow'
yield 'red'
light = traffic_light()
print(next(light)) # green
print(next(light)) # yellow
print(next(light)) # red
print(next(light)) # green (循环)
8. Python 3.8+中的新特性
8.1 海象运算符与迭代器
Python 3.8引入的海象运算符可以与迭代器结合使用:
python复制import random
def random_numbers():
while True:
yield random.random()
# 使用海象运算符捕获迭代器的值
gen = random_numbers()
while (num := next(gen)) < 0.9:
print(f"Got {num}")
8.2 可迭代解包增强
Python 3.9改进了可迭代对象的解包:
python复制first, *middle, last = range(10)
print(first) # 0
print(last) # 9
print(middle) # [1, 2, 3, 4, 5, 6, 7, 8]
8.3 类型注解支持
Python 3.9增强了类型注解对迭代器的支持:
python复制from typing import Iterator
def count_up_to(n: int) -> Iterator[int]:
i = 0
while i < n:
yield i
i += 1
9. 迭代器与循环神经网络(RNN)的类比
虽然迭代器是编程概念,RNN是机器学习模型,但它们都涉及"状态"和"序列处理"的核心思想:
- 迭代器维护内部状态(__next__调用之间的记忆)
- RNN也维护隐藏状态来处理序列数据
- 两者都按步骤处理输入,而不是一次性处理全部
这种相似性说明了迭代器模式在计算机科学中的普遍性。
10. 从迭代器到异步编程
Python的异步编程模型大量借鉴了迭代器/生成器的概念:
python复制import asyncio
async def async_counter(n):
for i in range(n):
yield i
await asyncio.sleep(0.1)
async def main():
async for i in async_counter(5):
print(i)
asyncio.run(main())
异步生成器(async/await)扩展了迭代器模式,使其能够处理I/O密集型任务。
理解迭代器不仅能让你的Python代码更高效,也是掌握生成器、协程和异步编程的基础。下次当你写for循环时,不妨想想背后强大的迭代器协议是如何工作的。
