可迭代对象与迭代器
什么是可迭代对象
可迭代对象是实现了__iter__方法的对象,它可以被for循环遍历。
# 常见的可迭代对象
numbers = [1, 2, 3] # 列表
text = "Hello" # 字符串
data = (1, 2, 3) # 元组
unique = {1, 2, 3} # 集合
mapping = {'a': 1, 'b': 2} # 字典
# 检查是否可迭代
from collections.abc import Iterable, Iterator
print(isinstance(numbers, Iterable)) # 输出: True
print(isinstance(numbers, Iterator)) # 输出: False
迭代协议
迭代协议定义了对象如何被迭代,需要实现__iter__和__next__方法。
class NumberRange:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start >= self.end:
raise StopIteration
current = self.start
self.start += 1
return current
# 使用自定义迭代器
numbers = NumberRange(1, 5)
for num in numbers:
print(num, end=" ") # 输出: 1 2 3 4
迭代器与可迭代对象的区别
可迭代对象可以被多次迭代,而迭代器是一次性的。
# 可迭代对象可以多次使用
my_list = [1, 2, 3]
print(list(my_list)) # 输出: [1, 2, 3]
print(list(my_list)) # 输出: [1, 2, 3] # 可以再次使用
# 迭代器只能使用一次
my_iter = iter([1, 2, 3])
print(list(my_iter)) # 输出: [1, 2, 3]
print(list(my_iter)) # 输出: [] # 已经耗尽
# 手动使用迭代器
my_iter = iter([10, 20, 30])
print(next(my_iter)) # 输出: 10
print(next(my_iter)) # 输出: 20
print(next(my_iter)) # 输出: 30
自定义迭代器
创建自定义迭代器需要实现迭代协议的两个方法。
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
result = self.a
self.a, self.b = self.b, self.a + self.b
self.count += 1
return result
# 使用斐波那契迭代器
fib = Fibonacci(10)
for num in fib:
print(num, end=" ") # 输出: 0 1 1 2 3 5 8 13 21 34
生成器函数
生成器函数使用yield语句创建迭代器,代码更简洁。
def countdown(n):
while n > 0:
yield n
n -= 1
# 使用生成器
for i in countdown(5):
print(i, end=" ") # 输出: 5 4 3 2 1
# 生成器表达式
squares = (x**2 for x in range(10))
print(list(squares)) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
itertools模块
itertools模块提供了强大的迭代器工具。
import itertools
# 无限计数器
counter = itertools.count(1, 2) # 从1开始,步长2
print([next(counter) for _ in range(5)]) # 输出: [1, 3, 5, 7, 9]
# 无限循环
colors = itertools.cycle(['红', '绿', '蓝'])
print([next(colors) for _ in range(6)]) # 输出: ['红', '绿', '蓝', '红', '绿', '蓝']
# 组合
items = ['A', 'B', 'C']
print(list(itertools.combinations(items, 2))) # 输出: [('A', 'B'), ('A', 'C'), ('B', 'C')]
# 排列
print(list(itertools.permutations(items, 2)))
# 输出: [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
迭代器的内存优势
迭代器采用惰性求值,一次只处理一个元素,节省内存。
# 列表方式(占用大量内存)
def get_squares_list(n):
return [x**2 for x in range(n)]
# 迭代器方式(内存友好)
def get_squares_iter(n):
for x in range(n):
yield x**2
# 处理大数据时,迭代器更高效
large_number = 1000000
# 这会占用大量内存
# squares_list = get_squares_list(large_number)
# 这不会一次性占用大量内存
for square in get_squares_iter(large_number):
if square > 100:
break
print(square, end=" ")
最佳实践
- 优先使用生成器函数而不是手动实现迭代器
- 使用
itertools模块处理复杂的迭代操作 - 处理大数据时使用迭代器节省内存
- 理解
StopIteration异常的使用场景 - 使用生成器表达式替代列表推导式节省内存
- 为迭代器添加有意义的
__repr__方法便于调试
掌握迭代器和生成器是编写高效Python代码的关键技能。