第七章 迭代器与生成器
经过对基本数据的学习,本章主要是对数据中的元素的遍历与生成的学习,大周末好好看好好学。未来就在你们的手中。
在 Python 中, 迭代器(Iterator) 是一种设计模式,也是一种对象,它允许你遍历一个容器(如列表、字典、集合等)中的所有元素,而无需了解其内部结构。
迭代器是一个实现了 迭代器协议的对象,该协议包含两个方法:
__iter__():返回迭代器对象本身__next__():返回容器中的下一个元素,如果没有更多元素则抛出
StopIteration 异常Python 的
for 循环、列表推导式等都依赖于迭代器协议:
# for 循环的底层工作方式my_list = [1, 2, 3]# 1. 获取迭代器iterator = iter(my_list) # 调用 my_list.__iter__()# 2. 重复调用 next()try: while True: element = next(iterator) # 调用 iterator.__next__() print(element)except StopIteration: pass # 遍历结束
# 列表的迭代器my_list = [1, 2, 3] list_iter = iter(my_list)print(next(list_iter)) # 1print(next(list_iter)) # 2print(next(list_iter)) # 3# print(next(list_iter)) # StopIteration 异常
class CountDown: def __init__(self, start): self.start = start def __iter__(self): return self def __next__(self): if self.start <= 0: raise StopIteration self.start -= 1 return self.start + 1# 使用自定义迭代器countdown = CountDown(3)for num in countdown: print(num) # 输出: 3, 2, 1
这两个概念经常被混淆:
| 概念 | 说明 | 示例 |
|---|---|---|
| 可迭代对象 (Iterable) | 实现了
__iter__() 方法的对象,可以被
for 循环遍历 |
list,
str,
dict,
set,
tuple |
| 迭代器 (Iterator) | 实现了
__iter__() 和
__next__() 方法的对象,是遍历的执行者 |
list_iterator,
dict_keyiterator, 生成器 |
my_list = [1, 2, 3]# my_list 是可迭代对象print(hasattr(my_list, '__iter__')) # True# 获取迭代器iterator = iter(my_list)print(hasattr(iterator, '__next__')) # Trueprint(hasattr(iterator, '__iter__')) # True
关键点:所有迭代器都是可迭代的,但并非所有可迭代对象都是迭代器。
Python 的
itertools 模块提供了强大的迭代器工具:
import itertools# 无限迭代器counter = itertools.count(1) # 1, 2, 3, ...repeater = itertools.repeat("hello", 3) # 'hello', 'hello', 'hello'# 组合迭代器numbers = [1, 2, 3]print(list(itertools.permutations(numbers, 2))) # [(1,2), (1,3), (2,1), ...]print(list(itertools.combinations(numbers, 2))) # [(1,2), (1,3), (2,3)]# 其他工具print(list(itertools.chain([1,2], [3,4]))) # [1, 2, 3, 4]print(list(itertools.islice(range(10), 5))) # [0, 1, 2, 3, 4]
迭代器只能遍历一次,遍历完成后就会"耗尽"。
my_list = [1, 2, 3] iterator = iter(my_list)# 第一次遍历print(list(iterator)) # [1, 2, 3]# 第二次遍历print(list(iterator)) # [] 空!迭代器已经耗尽# 解决方案:重新创建迭代器iterator = iter(my_list)print(list(iterator)) # [1, 2, 3]
在 Python 中, 生成器(Generator) 是一种特殊的 迭代器,它能以一种简洁、内存高效的方式生成一系列值。生成器的核心是 惰性求值——只在需要时才计算下一个值。
生成器是实现了 迭代器协议的函数或表达式,具有以下特点:
yield 时暂停,保留当前状态yield)def count_up_to(max_num): """生成从1到max_num的数字""" count = 1 while count <= max_num: yield count # 暂停并返回值 count += 1# 使用生成器counter = count_up_to(3)print(type(counter)) # <class 'generator'># 可以用 for 循环遍历for num in counter: print(num) # 输出: 1, 2, 3# 或者用 next() 逐个获取counter = count_up_to(3) # 需要重新创建print(next(counter)) # 1print(next(counter)) # 2print(next(counter)) # 3# print(next(counter)) # StopIteration 异常
# 语法类似列表推导式,但使用圆括号squares_gen = (x**2 for x in range(5))print(type(squares_gen)) # <class 'generator'># 遍历生成器for sq in squares_gen: print(sq) # 0, 1, 4, 9, 16# 与列表推导式的对比squares_list = [x**2 for x in range(5)] # 立即创建整个列表squares_gen = (x**2 for x in range(5)) # 惰性求值,按需计算
yield 关键字的工作原理
yield 是生成器的核心,它的工作方式:
yield 时,返回一个值并
暂停执行next() 时,从暂停处继续执行return,抛出
StopIterationdef simple_generator(): print("开始") yield 1
print("第一次暂停后") yield 2
print("第二次暂停后") yield 3
print("结束")
gen = simple_generator()print(next(gen)) # 开始\n1print(next(gen)) # 第一次暂停后\n2print(next(gen)) # 第二次暂停后\n3# print(next(gen)) # 结束\nStopIteration
yield from - 委托生成器def sub_generator(): yield "a" yield "b"def main_generator(): yield 1 yield from sub_generator() # 委托给另一个生成器 yield 2for item in main_generator(): print(item) # 1, 'a', 'b', 2
send() 方法def echo_generator(): while True:
received = yield # 接收外部发送的值
print(f"收到: {received}")
gen = echo_generator()next(gen) # 启动生成器gen.send("Hello") # 收到: Hellogen.send("World") # 收到: World
throw() 和
close()gen = count_up_to(5)print(next(gen)) # 1gen.throw(ValueError("手动抛出异常")) # 在生成器内部引发异常# 或者gen = count_up_to(5)
gen.close() # 关闭生成器,后续调用会抛出 StopIteration
| 特性 | 生成器 | 列表 |
|---|---|---|
| 内存使用 | 极低(只存当前值) | 高(存储所有值) |
| 创建速度 | 快(立即返回) | 慢(需计算所有值) |
| 访问方式 | 顺序访问,只能遍历一次 | 随机访问,可多次遍历 |
| 适用场景 | 大数据流、无限序列 | 小数据集、需要索引访问 |
# 处理大文件 - 生成器版本def read_file_lines(filename): with open(filename) as f: for line in f: yield line.strip()# 只占用一行的内存for line in read_file_lines("huge_file.txt"):
process(line)# 列表版本 - 会加载整个文件到内存lines = [line.strip() for line in open("huge_file.txt")]
生成器只能遍历一次,遍历完成后就会耗尽:
gen = (x for x in range(3))print(list(gen)) # [0, 1, 2]print(list(gen)) # [] 空!生成器已耗尽# 解决方案:重新创建gen = (x for x in range(3))print(list(gen)) # [0, 1, 2]
def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b# 获取前10个斐波那契数fib = fibonacci() first_10 = [next(fib) for _ in range(10)]print(first_10) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
def process_numbers(): # 原始数据 numbers = range(1, 101) # 过滤偶数 evens = (n for n in numbers if n % 2 == 0) # 计算平方 squares = (n**2 for n in evens) # 只取前10个 return itertools.islice(squares, 10) result = list(process_numbers())print(result) # [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
def natural_numbers(start=1): while True: yield start start += 1# 只计算需要的值first_5 = list(itertools.islice(natural_numbers(), 5))
class TreeNode: def __init__(self, value, left=None, right=None): self.value = value self.left = left self.right = right def inorder(self): """中序遍历生成器""" if self.left: yield from self.left.inorder() yield self.value if self.right: yield from self.right.inorder()# 使用root = TreeNode(2, TreeNode(1), TreeNode(3))for val in root.inorder(): print(val) # 1, 2, 3
✅ 适合使用生成器的场景:
❌ 不适合使用生成器的场景:
本文主要对遍历集合元素的两种访问方式即迭代器与生成器的学习。了解掌握他们的特性有助于在实际应用中提高访问效率。
相关资料获取:
公众号:咚咚王

《Python 编程:从入门到实践》
《利用 Python 进行数据分析》
《算法导论中文第三版》
《概率论与数理统计(第四版) (盛骤) 》
《程序员的数学》
《线性代数应该这样学第 3 版》
《微积分和数学分析引论》
《(西瓜书)周志华-机器学习》
《TensorFlow 机器学习实战指南》
《Sklearn 与 TensorFlow 机器学习实用指南》
《模式识别(第四版)》
《深度学习 deep learning》伊恩·古德费洛著 花书
《Python 深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》
《深入浅出神经网络与深度学习 +(迈克尔·尼尔森(Michael+Nielsen) 》
《自然语言处理综论 第 2 版》
《Natural-Language-Processing-with-PyTorch》
《计算机视觉-算法与应用(中文版)》
《Learning OpenCV 4》
《AIGC:智能创作时代》杜雨 +&+ 张孜铭
《AIGC 原理与实践:零基础学大语言模型、扩散模型和多模态模型》
《从零构建大语言模型(中文版)》
《实战 AI 大模型》
《AI 3.0》
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048224/viewspace-3102013/ ,如需转载,请注明出处,否则将追究法律责任。