Python迭代器与生成器:原理、实现与应用

📅 2026/7/19 2:04:47
Python迭代器与生成器:原理、实现与应用
1. 迭代器基础概念与实现原理迭代器是Python中用于遍历集合元素的核心机制。简单来说迭代器就是一个带状态的对象它能记住当前遍历的位置。想象你正在阅读一本书迭代器就像你的书签记录着你当前读到哪一页每次需要继续阅读时都能准确地翻到上次停下的位置。Python中的迭代器协议要求实现两个特殊方法__iter__()返回迭代器对象本身__next__()返回下一个元素如果没有元素则抛出StopIteration异常让我们看一个简单的列表迭代示例fruits [apple, banana, cherry] fruit_iter iter(fruits) # 等同于 fruits.__iter__() print(next(fruit_iter)) # apple print(next(fruit_iter)) # banana print(next(fruit_iter)) # cherry print(next(fruit_iter)) # 抛出StopIteration异常1.1 自定义迭代器类我们可以创建自己的迭代器类来实现特定遍历逻辑。下面是一个生成平方数的迭代器示例class SquareNumbers: def __init__(self, max_num): self.max max_num self.current 0 def __iter__(self): return self def __next__(self): if self.current self.max: raise StopIteration result self.current ** 2 self.current 1 return result # 使用示例 squares SquareNumbers(5) for num in squares: print(num) # 输出: 0 1 4 9 16注意迭代器是一次性对象遍历结束后再次迭代不会得到任何结果。如果需要多次遍历要么重新创建迭代器要么考虑使用可迭代对象。2. 生成器更优雅的迭代器实现生成器是创建迭代器的简洁方式它通过yield关键字自动实现迭代器协议。与普通函数不同生成器函数在调用时不会立即执行而是返回一个生成器对象只有在迭代时才会逐步执行。2.1 生成器函数基础下面是一个简单的生成器示例生成指定范围内的偶数def even_numbers(max_num): num 0 while num max_num: yield num num 2 # 使用方式1直接迭代 for n in even_numbers(10): print(n) # 0 2 4 6 8 10 # 使用方式2手动控制 evens even_numbers(10) print(next(evens)) # 0 print(next(evens)) # 2生成器的核心特点是执行到yield时暂停返回右侧表达式的值下次调用next()时从暂停处继续执行函数结束时自动抛出StopIteration2.2 生成器表达式除了函数形式Python还提供了类似列表推导式的生成器表达式语法# 列表推导式立即计算 squares_list [x**2 for x in range(5)] # [0, 1, 4, 9, 16] # 生成器表达式惰性计算 squares_gen (x**2 for x in range(5)) print(next(squares_gen)) # 0 print(next(squares_gen)) # 1生成器表达式特别适合处理大数据集因为它不会一次性占用大量内存。3. 迭代器与生成器的实际应用场景3.1 处理大型文件当处理GB级别的日志文件时使用生成器可以避免内存溢出def read_large_file(file_path): with open(file_path, r) as f: while True: line f.readline() if not line: break yield line.strip() # 逐行处理内存友好 for line in read_large_file(huge_log.txt): process_line(line)3.2 无限序列生成生成器非常适合表示无限序列如斐波那契数列def fibonacci(): a, b 0, 1 while True: yield a a, b b, a b fib fibonacci() print(next(fib)) # 0 print(next(fib)) # 1 print(next(fib)) # 1 print(next(fib)) # 23.3 数据管道处理可以串联多个生成器构建数据处理管道def filter_odd(numbers): for n in numbers: if n % 2 ! 0: yield n def square(numbers): for n in numbers: yield n ** 2 numbers range(10) pipeline square(filter_odd(numbers)) print(list(pipeline)) # [1, 9, 25, 49, 81]4. 高级技巧与性能优化4.1 yield from语法Python 3.3引入的yield from可以简化嵌套生成器的代码# 旧写法 def flatten(nested): for sublist in nested: for item in sublist: yield item # 新写法 def flatten(nested): for sublist in nested: yield from sublist4.2 生成器与协程生成器可以通过.send()方法实现简单的协程def coroutine(): print(Starting coroutine) while True: received yield print(fReceived: {received}) co coroutine() next(co) # 启动协程 co.send(Hello) # 输出: Received: Hello co.send(World) # 输出: Received: World4.3 性能对比我们比较三种计算平方和的方式import time def squares_list(n): return [x**2 for x in range(n)] def squares_gen(n): return (x**2 for x in range(n)) def squares_yield(n): for x in range(n): yield x**2 n 1000000 # 列表方式内存最高 start time.time() sum(squares_list(n)) print(fList: {time.time()-start:.4f}s) # 生成器表达式 start time.time() sum(squares_gen(n)) print(fGenexpr: {time.time()-start:.4f}s) # yield函数 start time.time() sum(squares_yield(n)) print(fYield: {time.time()-start:.4f}s)典型输出结果List: 0.1253s Genexpr: 0.1107s Yield: 0.1098s虽然性能差异不大但生成器版本的内存效率要高得多。5. 常见问题与调试技巧5.1 生成器耗尽问题生成器只能迭代一次再次迭代不会得到任何结果numbers (x for x in range(3)) print(list(numbers)) # [0, 1, 2] print(list(numbers)) # []解决方案是重新创建生成器或者使用itertools.tee复制生成器。5.2 调试生成器可以使用inspect模块检查生成器状态import inspect def simple_gen(): yield 1 yield 2 gen simple_gen() print(inspect.getgeneratorstate(gen)) # GEN_CREATED next(gen) print(inspect.getgeneratorstate(gen)) # GEN_SUSPENDED next(gen) print(inspect.getgeneratorstate(gen)) # GEN_CLOSED5.3 异常处理生成器内部可以使用try/finally确保资源释放def db_reader(query): db connect_to_database() try: for record in db.execute(query): yield record finally: db.close() # 确保数据库连接会被关闭6. 最佳实践与设计模式6.1 何时使用生成器适合使用生成器的场景处理大量数据或无限序列需要节省内存构建数据处理管道实现惰性计算6.2 生成器与类迭代器的选择选择依据简单迭代逻辑 → 生成器函数复杂状态管理 → 迭代器类需要额外方法 → 迭代器类代码简洁性 → 生成器6.3 内存优化技巧对于大型数据集# 不好消耗大量内存 big_list [x for x in range(1000000)] # 好内存友好 big_gen (x for x in range(1000000))在数据处理流水线中尽量保持数据在生成器间流动避免转换为列表。