一、迭代器协议:__iter__和__next__的魔法
迭代器的本质
Python中的迭代器不是存储所有元素的容器,而是惰性计算的协议实现。核心在于两个方法:
__iter__():返回迭代器自身__next__():返回下一个元素,耗尽时抛出StopIteration
python
class CountDown:
"""自定义迭代器:倒计时"""
def __init__(self, start):
self.current = start
def __iter__(self):
return self # 迭代器必须返回自身
def __next__(self):
if self.current <= 0:
raise StopIteration
num = self.current
self.current -= 1
return num
# 使用
for num in CountDown(5):
print(num) # 输出: 5 4 3 2 1
迭代器的优势
- 内存高效:不一次性加载所有数据
- 无限序列:可以表示无限长的序列
- 通用接口 :统一的
for循环处理方式
二、生成器:yield的暂停与恢复魔法
生成器函数
生成器是创建迭代器的语法糖 ,使用yield暂停函数执行并返回值:
python
def fibonacci_generator(limit):
"""生成斐波那契数列"""
a, b = 0, 1
count = 0
while count < limit:
yield a # 暂停执行,返回a
a, b = b, a + b
count += 1
# 生成器对象
fib_gen = fibonacci_generator(10)
print(next(fib_gen)) # 0
print(next(fib_gen)) # 1
print(list(fib_gen)) # [1, 2, 3, 5, 8, 13, 21, 34]
生成器表达式
更简洁的生成器创建方式:
python
# 传统列表推导(立即计算)
squares_list = [x**2 for x in range(1000000)] # 占用大量内存
# 生成器表达式(惰性计算)
squares_gen = (x**2 for x in range(1000000)) # 几乎不占内存
print(next(squares_gen)) # 0
print(next(squares_gen)) # 1
三、yield from:生成器的委派机制
简化嵌套生成器
python
def chain_generators(*iterables):
"""连接多个可迭代对象"""
for iterable in iterables:
yield from iterable # 委派给子生成器
# 等效于:
# for item in iterable:
# yield item
result = list(chain_generators([1, 2], 'ab', (True, False)))
# [1, 2, 'a', 'b', True, False]
四、生成器的高级用法
1. 协程:双向通信
python
def coroutine_generator():
"""接收外部数据的生成器"""
total = 0
while True:
value = yield total # 暂停并接收发送的值
if value is None:
break
total += value
coro = coroutine_generator()
next(coro) # 启动生成器(预激)
print(coro.send(10)) # 10
print(coro.send(20)) # 30
coro.close() # 关闭生成器
2. 上下文管理
python
from contextlib import contextmanager
@contextmanager
def managed_resource():
"""生成器实现的上下文管理器"""
print("获取资源")
resource = "资源对象"
try:
yield resource
finally:
print("释放资源")
with managed_resource() as r:
print(f"使用 {r}")
五、性能对比:迭代器 vs 列表
python
import time
import sys
def test_memory_usage():
"""内存使用对比"""
# 列表:一次性加载所有数据
list_data = [i for i in range(1000000)]
print(f"列表内存: {sys.getsizeof(list_data):,} bytes")
# 生成器:惰性计算
gen_data = (i for i in range(1000000))
print(f"生成器内存: {sys.getsizeof(gen_data):,} bytes")
def test_performance():
"""性能对比"""
n = 10_000_000
# 列表推导
start = time.time()
_ = [x**2 for x in range(n)]
list_time = time.time() - start
# 生成器表达式
start = time.time()
_ = (x**2 for x in range(n))
gen_time = time.time() - start
print(f"列表推导: {list_time:.3f}s")
print(f"生成器表达式: {gen_time:.3f}s")
test_memory_usage()
test_performance()
六、实用模式与陷阱
1. 生成器的一次性使用
python
gen = (x for x in range(3))
print(list(gen)) # [0, 1, 2]
print(list(gen)) # [] !已耗尽
2. itertools模块的迭代器工具
python
from itertools import islice, count, cycle
# 无限序列的切片
first_10 = list(islice(count(10), 5)) # [10, 11, 12, 13, 14]
# 循环迭代器
cycler = cycle('ABC')
print([next(cycler) for _ in range(6)]) # ['A', 'B', 'C', 'A', 'B', 'C']
3. 自定义可迭代对象
python
class BatchProcessor:
"""分批处理大数据集"""
def __init__(self, data, batch_size):
self.data = data
self.batch_size = batch_size
def __iter__(self):
"""返回生成器迭代器"""
for i in range(0, len(self.data), self.batch_size):
yield self.data[i:i + self.batch_size]
data = list(range(100))
batcher = BatchProcessor(data, 10)
for batch in batcher:
process(batch) # 每次处理10个元素
总结
迭代器和生成器是Python惰性计算哲学的体现,它们通过:
- 按需计算节省内存
- 统一的迭代协议简化API设计
- 生成器协程实现复杂控制流
- 优雅的语法让代码更清晰