迭代器是 Python 中实现迭代协议的对象,允许你逐个访问容器中的元素,而无需提前知道容器的内部结构。迭代器是 Python 实现 for 循环的基础。
一、迭代器
迭代器是一个实现了迭代器协议的对象,即实现了 __iter__() 和 __next__() 方法。
| __iter__() | 返回迭代器对象本身 |
| __next__() | 返回下一个元素,没有元素时抛出 StopIteration |
可迭代对象 vs 迭代器
# 可迭代对象(Iterable):实现了 __iter__() 方法
# 迭代器(Iterator):同时实现了 __iter__() 和 __next__() 方法
# 列表是可迭代对象,不是迭代器
my_list = [1, 2, 3]
print(dir(my_list)) # 有 __iter__,没有 __next__
# 获取迭代器
iterator = iter(my_list)
print(dir(iterator)) # 有 __iter__ 和 __next__
# 手动迭代
print(next(iterator)) # 1
print(next(iterator)) # 2
print(next(iterator)) # 3
# print(next(iterator)) # StopIteration
二、迭代器的基本使用
1. 手动迭代
# 使用 iter() 和 next()
colors = ['red', 'green', 'blue']
iterator = iter(colors)
print(next(iterator)) # red
print(next(iterator)) # green
print(next(iterator)) # blue
# print(next(iterator)) # StopIteration
2. 使用 for 循环自动迭代
# for 循环内部自动调用 iter() 和 next()
for color in colors:
print(color)
# 等价于:
iterator = iter(colors)
while True:
try:
color = next(iterator)
print(color)
except StopIteration:
break
3. 检测是否可迭代
from collections.abc import Iterable, Iterator
# 判断是否可迭代
print(isinstance([1, 2, 3], Iterable)) # True
print(isinstance(123, Iterable)) # False
# 判断是否是迭代器
print(isinstance(iter([1, 2, 3]), Iterator)) # True
print(isinstance([1, 2, 3], Iterator)) # False
三、自定义迭代器
1. 实现迭代器协议
class MyRange:
"""自定义一个类似 range 的迭代器"""
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
value = self.current
self.current += 1
return value
# 使用
for num in MyRange(1, 5):
print(num) # 1, 2, 3, 4
# 也可以手动迭代
mr = MyRange(1, 3)
print(next(mr)) # 1
print(next(mr)) # 2
2. 斐波那契数列迭代器
class Fibonacci:
"""斐波那契数列迭代器"""
def __init__(self, max_count):
self.max_count = max_count
self.count = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.count >= self.max_count:
raise StopIteration
if self.count == 0:
self.count += 1
return self.a
elif self.count == 1:
self.count += 1
return self.b
self.a, self.b = self.b, self.a + self.b
self.count += 1
return self.b
for num in Fibonacci(10):
print(num, end=' ') # 0 1 1 2 3 5 8 13 21 34
四、内置迭代器工具
1. enumerate – 带索引的迭代
fruits = ['apple', 'banana', 'orange']
# enumerate 返回迭代器,产生 (index, value) 元组
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# 指定起始索引
for i, fruit in enumerate(fruits, start=1):
print(f"{i}: {fruit}")
2. zip – 并行迭代
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
scores = [85, 92, 78]
# zip 返回迭代器,产生元组
for name, age, score in zip(names, ages, scores):
print(f"{name}, {age}岁, {score}分")
# 转换为列表
pairs = list(zip(names, ages))
print(pairs) # [('Alice', 25), ('Bob', 30), ('Charlie', 35)]
3. map – 映射迭代
numbers = [1, 2, 3, 4, 5]
# map 返回迭代器
squares = map(lambda x: x ** 2, numbers)
print(list(squares)) # [1, 4, 9, 16, 25]
# 多个序列
a = [1, 2, 3]
b = [10, 20, 30]
sums = map(lambda x, y: x + y, a, b)
print(list(sums)) # [11, 22, 33]
4. filter – 过滤迭代
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# filter 返回迭代器,只保留满足条件的元素
even = filter(lambda x: x % 2 == 0, numbers)
print(list(even)) # [2, 4, 6, 8, 10]
# 等价于列表推导式
even = [x for x in numbers if x % 2 == 0]
5. itertools 模块
import itertools
# 无限迭代器
counter = itertools.count(start=1, step=2) # 1, 3, 5, 7, …
for i, val in zip(range(5), counter):
print(val, end=' ') # 1 3 5 7 9
# 循环迭代器
cycle = itertools.cycle(['A', 'B', 'C'])
for i, val in zip(range(6), cycle):
print(val, end=' ') # A B C A B C
# 排列组合
perms = itertools.permutations([1, 2, 3], 2)
print(list(perms)) # [(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)]
combs = itertools.combinations([1, 2, 3], 2)
print(list(combs)) # [(1,2), (1,3), (2,3)]
五、迭代器的优势
1. 惰性求值(节省内存)
# 传统方式:一次性生成所有数据,占用大量内存
def get_numbers_traditional(n):
result = []
for i in range(n):
result.append(i ** 2)
return result
# 迭代器方式:逐个生成,节省内存
def get_numbers_iterative(n):
for i in range(n):
yield i ** 2 # 生成器函数返回迭代器
# 处理大规模数据
traditional = get_numbers_traditional(1000000) # 占用大量内存
iterative = get_numbers_iterative(1000000) # 几乎不占内存
2. 处理无限序列
# 迭代器可以表示无限序列
def infinite_numbers():
n = 0
while True:
yield n
n += 1
# 只取前 10 个
for num in infinite_numbers():
if num >= 10:
break
print(num, end=' ') # 0 1 2 3 4 5 6 7 8 9
3. 单次遍历
numbers = [1, 2, 3]
iterator = iter(numbers)
print(list(iterator)) # [1, 2, 3]
print(list(iterator)) # [](迭代器已耗尽)
六、迭代器 vs 序列对比
| 内存占用 | 大(存储所有元素) | 小(一次只存一个) |
| 访问方式 | 随机访问(索引) | 顺序访问(next) |
| 遍历次数 | 可多次遍历 | 只能遍历一次 |
| 无限序列 | 不支持 | 支持 |
| 适用场景 | 数据量小、需要随机访问 | 数据量大、只需遍历一次 |
七、常见错误
1. 迭代器一次性
numbers = [1, 2, 3]
it = iter(numbers)
print(sum(it)) # 6
print(sum(it)) # 0(迭代器已耗尽)
# 解决方案:重新创建迭代器
it = iter(numbers)
print(list(it)) # [1, 2, 3]
2. 修改容器时迭代
# 错误:迭代时修改容器
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # 可能导致跳过元素
print(numbers) # [1, 3, 5](看似正确,但行为不确定)
# 正确:迭代副本
for num in numbers[:]: # 使用切片副本
if num % 2 == 0:
numbers.remove(num)
# 正确:使用列表推导式
numbers = [num for num in numbers if num % 2 != 0]
八、生成器:迭代器的简便实现
生成器是使用 yield 关键字创建迭代器的简便方式。
# 生成器函数
def my_range(n):
i = 0
while i < n:
yield i
i += 1
for num in my_range(5):
print(num, end=' ') # 0 1 2 3 4
# 生成器表达式
squares = (x ** 2 for x in range(10))
print(type(squares)) # <class 'generator'>
# 生成器与列表推导式的区别
list_comp = [x ** 2 for x in range(10)] # 列表(立即计算)
gen_exp = (x ** 2 for x in range(10)) # 生成器(惰性计算)
其他
| 可迭代对象 | __iter__() | 可以被 iter() 转换为迭代器 |
| 迭代器 | __iter__() + __next__() | 支持 next() 调用 |
| 生成器 | yield | 用函数语法创建迭代器 |
| 生成器表达式 | (x for x in …) | 类似列表推导式,惰性求值 |
核心要点:
迭代器通过 __iter__ 和 __next__ 实现
for 循环自动处理迭代器的 StopIteration
迭代器惰性求值,节省内存
迭代器只能遍历一次
生成器是创建迭代器的简便方式
