一、什么是迭代器?
1. 迭代器的定义
迭代器是一个可以记住遍历位置的对象。它实现了迭代器协议,即包含 __iter__() 和 __next__() 方法。
2. 迭代器协议
# 迭代器必须实现的两个方法:- __iter__(): 返回迭代器对象本身- __next__(): 返回下一个元素,没有元素时抛出 StopIteration
3. 可迭代对象 vs 迭代器
# 可迭代对象 (Iterable): 可以返回迭代器的对象(实现了 __iter__)# 迭代器 (Iterator): 可以逐个返回元素的对象(实现了 __iter__ 和 __next__)# 关系图:# 可迭代对象 ──(iter())──> 迭代器 ──(next())──> 元素
二、基础概念
1. 最简单的例子
# 列表是可迭代对象,但不是迭代器my_list = [1, 2, 3]print(f"列表是可迭代对象: {hasattr(my_list, '__iter__')}")print(f"列表是迭代器: {hasattr(my_list, '__next__')}")# 获取迭代器iterator = iter(my_list)print(f"迭代器是可迭代对象: {hasattr(iterator, '__iter__')}")print(f"迭代器是迭代器: {hasattr(iterator, '__next__')}")# 使用迭代器print(next(iterator)) # 1print(next(iterator)) # 2print(next(iterator)) # 3# print(next(iterator)) # StopIteration
2. 迭代器的工作原理
# for 循环的工作原理my_list = [1, 2, 3]# Python 内部是这样做的:iterator = iter(my_list) # 1. 获取迭代器while True: try: item = next(iterator) # 2. 获取下一个元素 print(item) # 3. 处理元素 except StopIteration: # 4. 捕获结束信号 break # 5. 退出循环# 等价于:for item in my_list: print(item)
三、自定义迭代器
1. 最简单的迭代器
class Counter: """计数器迭代器""" 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# 使用counter = Counter(1, 5)for num in counter: print(num, end=' ') # 1 2 3 4print()# 注意:迭代器只能使用一次print(list(counter)) # [] 已经用完了
2. 无限迭代器
class FibonacciIterator: """斐波那契数列迭代器(无限)""" def __init__(self): self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): value = self.a self.a, self.b = self.b, self.a + self.b return value# 使用fib = FibonacciIterator()for i, num in enumerate(fib): print(num, end=' ') if i >= 10: # 取前10个 breakprint() # 0 1 1 2 3 5 8 13 21 34 55# 注意:无限迭代器需要手动停止
3. 可重置的迭代器
class ResettableIterator: """可重置的迭代器""" def __init__(self, data): self.data = data self.index = 0 def __iter__(self): return self def __next__(self): if self.index >= len(self.data): raise StopIteration value = self.data[self.index] self.index += 1 return value def reset(self): """重置迭代器""" self.index = 0# 使用it = ResettableIterator([1, 2, 3, 4, 5])print("第一次遍历:")for item in it: print(item, end=' ')print()print("重置后再次遍历:")it.reset()for item in it: print(item, end=' ')print()
四、内置迭代器工具
1. iter() 函数
# 从可迭代对象创建迭代器my_list = [1, 2, 3]it = iter(my_list)print(next(it)) # 1# 使用哨兵值创建迭代器import sysdef read_until_q(): """读取输入直到输入 'q'""" return input("输入 (输入 'q' 退出): ")# 当函数返回 'q' 时停止for line in iter(read_until_q, 'q'): print(f"你输入了: {line}")
2. next() 函数
it = iter([1, 2, 3])# 基本使用print(next(it)) # 1# 带默认值print(next(it, '没有更多了')) # 2print(next(it, '没有更多了')) # 3print(next(it, '没有更多了')) # '没有更多了'
3. enumerate() - 枚举迭代器
fruits = ['apple', 'banana', 'orange']# 获取索引和值for i, fruit in enumerate(fruits): print(f"{i}: {fruit}")# 指定起始索引for i, fruit in enumerate(fruits, start=1): print(f"{i}: {fruit}")
4. zip() - 并行迭代
names = ['Alice', 'Bob', 'Charlie']ages = [25, 30, 35]cities = ['New York', 'London', 'Tokyo']# 并行迭代多个序列for name, age, city in zip(names, ages, cities): print(f"{name} is {age} years old, lives in {city}")# 处理不等长序列numbers = [1, 2, 3]letters = ['a', 'b']for num, letter in zip(numbers, letters): print(f"{num}:{letter}") # 只输出两个,第三个被忽略# 使用 zip_longest 处理不等长from itertools import zip_longestfor num, letter in zip_longest(numbers, letters, fillvalue='?'): print(f"{num}:{letter}")
五、最佳实践和注意事项
1. 迭代器使用原则
class IteratorBestPractices: """迭代器最佳实践""" # 1. 一次性的迭代器 def once_demo(self): it = iter([1, 2, 3]) print(list(it)) # [1, 2, 3] print(list(it)) # [] - 已经用完了 # 2. 使用生成器简化 def generator_demo(self): def countdown(n): while n > 0: yield n n -= 1 # 简单清晰 for x in countdown(5): print(x) # 3. 处理大文件 def file_processing_demo(self): def read_lines(file_path): with open(file_path) as f: for line in f: yield line.strip() # 内存友好 for line in read_lines('large_file.txt'): process(line) # 4. 提前退出 def early_exit_demo(self): def find_first(iterable, predicate): for item in iterable: if predicate(item): return item return None # 找到就停止,不继续遍历 result = find_first(range(1000000), lambda x: x > 500000)
2. 常见陷阱
# 陷阱1:多次使用迭代器it = iter([1, 2, 3])print(list(it)) # [1, 2, 3]print(list(it)) # [] - 已经空了# 正确做法:重新创建it = iter([1, 2, 3])print(list(it))it = iter([1, 2, 3]) # 重新创建print(list(it))# 陷阱2:修改可迭代对象data = [1, 2, 3, 4]for item in data: if item == 2: data.remove(item) # 危险!会跳过元素print(data) # [1, 3, 4] - 3 被跳过了# 正确做法:创建新列表data = [1, 2, 3, 4]data = [x for x in data if x != 2]# 陷阱3:迭代器耗尽def process_items(items): for item in items: yield process(item)items = process_items(data)if items: # 错误:迭代器总是 True print("有数据")# 正确做法items = list(process_items(data)) # 转换为列表if items: print("有数据")# 陷阱4:无限迭代器没有停止条件def infinite(): i = 0 while True: yield i i += 1gen = infinite()# for x in gen: # 无限循环!# print(x)# 正确做法:设置限制for i, x in enumerate(gen): if i >= 10: break print(x)
3. 自定义迭代器模板
class IteratorTemplate: """迭代器模板""" def __init__(self, data): self.data = data self.index = 0 def __iter__(self): """返回迭代器本身""" return self def __next__(self): """返回下一个元素""" if self.index >= len(self.data): raise StopIteration value = self._process_item(self.data[self.index]) self.index += 1 return value def _process_item(self, item): """处理单个项目(可被子类重写)""" return item def reset(self): """重置迭代器""" self.index = 0 def __len__(self): """返回可迭代长度""" return len(self.data) - self.index def __repr__(self): return f"{self.__class__.__name__}(剩余: {len(self)})"# 使用class SquareIterator(IteratorTemplate): def _process_item(self, item): return item ** 2it = SquareIterator([1, 2, 3, 4, 5])for value in it: print(value, end=' ') # 1 4 9 16 25print()print(it) # SquareIterator(剩余: 0)
总结
迭代器的优点:
内存高效:一次只产生一个元素
惰性计算:需要时才计算
无限序列:可以表示无限数据流
统一接口:所有迭代器使用相同的方式操作
何时使用迭代器:
处理大数据集
流式数据处理
需要惰性计算的场景
表示无限序列
需要统一的遍历接口
何时避免使用迭代器: