Python 中的迭代器和生成器有什么区别?
Python 迭代器与生成器详解迭代器(Iterator)什么是迭代器迭代器是一个实现了迭代协议的对象,它包含两个方法:__iter__():返回迭代器对象本身__next__():返回容器的下一个元素,如果没有更多元素则抛出 StopIteration 异常迭代器示例class MyIterator: 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# 使用迭代器my_iter = MyIterator([1, 2, 3, 4, 5])for item in my_iter: print(item)迭代器的特性惰性求值:只在需要时才计算下一个值节省内存:不需要一次性存储所有数据单向遍历:只能向前遍历,不能回退一次性使用:迭代器遍历后就不能再次使用# 迭代器的一次性特性my_list = [1, 2, 3]my_iter = iter(my_list)print(list(my_iter)) # [1, 2, 3]print(list(my_iter)) # [] - 迭代器已耗尽可迭代对象(Iterable)什么是可迭代对象可迭代对象是实现了 __iter__() 方法的对象,该方法返回一个迭代器。常见的可迭代对象包括列表、元组、字符串、字典、集合等。可迭代对象示例# 内置可迭代对象my_list = [1, 2, 3]my_tuple = (1, 2, 3)my_string = "hello"my_dict = {'a': 1, 'b': 2}my_set = {1, 2, 3}# 检查是否可迭代from collections.abc import Iterableprint(isinstance(my_list, Iterable)) # Trueprint(isinstance(123, Iterable)) # False可迭代对象与迭代器的关系# 可迭代对象通过 iter() 函数获取迭代器my_list = [1, 2, 3]my_iterator = iter(my_list)print(next(my_iterator)) # 1print(next(my_iterator)) # 2print(next(my_iterator)) # 3# print(next(my_iterator)) # StopIteration生成器(Generator)什么是生成器生成器是一种特殊的迭代器,使用函数和 yield 语句来创建。生成器函数在执行过程中会暂停并保存当前状态,下次调用时从暂停处继续执行。生成器函数示例def simple_generator(): yield 1 yield 2 yield 3# 使用生成器gen = simple_generator()print(next(gen)) # 1print(next(gen)) # 2print(next(gen)) # 3生成器表达式# 生成器表达式(类似列表推导式)gen_expr = (x * x for x in range(10))print(list(gen_expr)) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]# 生成器表达式节省内存# 列表推导式list_comp = [x * x for x in range(1000000)] # 占用大量内存# 生成器表达式gen_expr = (x * x for x in range(1000000)) # 几乎不占用内存生成器的优势内存效率:不需要一次性生成所有值惰性计算:只在需要时才计算值无限序列:可以表示无限长的序列管道处理:可以串联多个生成器# 无限序列生成器def infinite_sequence(): num = 0 while True: yield num num += 1# 使用无限序列gen = infinite_sequence()for i in range(10): print(next(gen)) # 0, 1, 2, ..., 9迭代器与生成器的对比相同点都实现了迭代协议都支持惰性求值都可以使用 next() 函数获取下一个值都可以在 for 循环中使用不同点| 特性 | 迭代器 | 生成器 ||------|--------|--------|| 实现方式 | 实现 __iter__ 和 __next__ 方法 | 使用 yield 语句 || 代码复杂度 | 需要手动管理状态 | 自动管理状态 || 内存占用 | 需要存储所有数据 | 只保存当前状态 || 代码简洁性 | 相对复杂 | 更简洁 |代码对比# 迭代器实现class SquaresIterator: def __init__(self, n): self.n = n self.current = 0 def __iter__(self): return self def __next__(self): if self.current >= self.n: raise StopIteration result = self.current ** 2 self.current += 1 return result# 生成器实现def squares_generator(n): for i in range(n): yield i ** 2# 使用对比print("迭代器:", list(SquaresIterator(5))) # [0, 1, 4, 9, 16]print("生成器:", list(squares_generator(5))) # [0, 1, 4, 9, 16]实际应用场景1. 处理大文件def read_large_file(file_path): """逐行读取大文件,避免内存溢出""" with open(file_path, 'r') as file: for line in file: yield line.strip()# 使用生成器处理大文件for line in read_large_file('large_file.txt'): process_line(line) # 处理每一行2. 数据管道def read_data(source): """读取数据""" for item in source: yield itemdef filter_data(data, predicate): """过滤数据""" for item in data: if predicate(item): yield itemdef transform_data(data, func): """转换数据""" for item in data: yield func(item)# 使用数据管道data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]pipeline = transform_data( filter_data( read_data(data), lambda x: x % 2 == 0 # 过滤偶数 ), lambda x: x * 2 # 转换为两倍)print(list(pipeline)) # [4, 8, 12, 16, 20]3. 斐波那契数列def fibonacci(): """生成斐波那契数列""" a, b = 0, 1 while True: yield a a, b = b, a + b# 获取前 10 个斐波那契数fib = fibonacci()fib_sequence = [next(fib) for _ in range(10)]print(fib_sequence) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]4. 批量处理数据def batch_generator(data, batch_size): """将数据分批处理""" for i in range(0, len(data), batch_size): yield data[i:i + batch_size]# 使用批量生成器data = list(range(100))for batch in batch_generator(data, 10): print(f"处理批次: {batch}")生成器的高级用法1. yield fromdef sub_generator(): yield 1 yield 2def main_generator(): yield from sub_generator() # 委托给子生成器 yield 3print(list(main_generator())) # [1, 2, 3]2. 生成器发送值def accumulator(): total = 0 while True: value = yield total if value is not None: total += valueacc = accumulator()next(acc) # 启动生成器print(acc.send(10)) # 10print(acc.send(20)) # 30print(acc.send(30)) # 603. 生成器抛出异常def my_generator(): try: while True: value = yield print(f"收到值: {value}") except ValueError: print("捕获到 ValueError") finally: print("生成器关闭")gen = my_generator()next(gen)gen.send(1) # 收到值: 1gen.throw(ValueError) # 捕获到 ValueErrorgen.close() # 生成器关闭性能对比import timeimport sys# 内存使用对比def list_comprehension(n): return [i ** 2 for i in range(n)]def generator_expression(n): return (i ** 2 for i in range(n))# 内存占用list_obj = list_comprehension(1000000)gen_obj = generator_expression(1000000)print(f"列表占用内存: {sys.getsizeof(list_obj)} 字节")print(f"生成器占用内存: {sys.getsizeof(gen_obj)} 字节")# 执行时间对比start = time.time()sum([i ** 2 for i in range(1000000)])print(f"列表推导式耗时: {time.time() - start:.4f} 秒")start = time.time()sum(i ** 2 for i in range(1000000))print(f"生成器表达式耗时: {time.time() - start:.4f} 秒")最佳实践1. 选择合适的工具# 需要多次访问数据 - 使用列表data = [1, 2, 3, 4, 5]result1 = sum(data)result2 = max(data)# 只需要一次遍历 - 使用生成器data = (i for i in range(1000000))result = sum(data)2. 避免过早求值# 不好的做法def get_all_data(): return [process_item(item) for item in large_dataset]# 好的做法def get_data_generator(): for item in large_dataset: yield process_item(item)3. 使用 itertools 模块import itertools# 无限计数器counter = itertools.count(start=0, step=2)print(list(itertools.islice(counter, 5))) # [0, 2, 4, 6, 8]# 循环迭代器cycle = itertools.cycle([1, 2, 3])print(list(itertools.islice(cycle, 7))) # [1, 2, 3, 1, 2, 3, 1]# 链接迭代器chain = itertools.chain([1, 2], [3, 4], [5, 6])print(list(chain)) # [1, 2, 3, 4, 5, 6]总结迭代器实现了 __iter__ 和 __next__ 方法手动管理状态适合复杂的迭代逻辑可以重复创建生成器使用 yield 语句创建自动管理状态代码更简洁内存效率更高适合数据流处理使用建议小数据集:使用列表或元组大数据集:使用生成器复杂逻辑:使用迭代器类数据管道:使用生成器表达式无限序列:使用生成器函数理解迭代器和生成器的区别,能够帮助编写更高效、更优雅的 Python 代码。