
第七章 迭代器与生成器
经过对基本数据的学习,本章主要是对数据中的元素的遍历与生成的学习,大周末好好看好好学。未来就在你们的手中。
在 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)) # 1
print(next(list_iter)) # 2
print(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) | 实现了 |
|
迭代器 (Iterator) | 实现了 |
|
my_list = [1, 2, 3]
# my_list 是可迭代对象
print(hasattr(my_list, '__iter__')) # True
# 获取迭代器
iterator = iter(my_list)
print(hasattr(iterator, '__next__')) # True
print(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)) # 1
print(next(counter)) # 2
print(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)) # 开始\n1
print(next(gen)) # 第一次暂停后\n2
print(next(gen)) # 第二次暂停后\n3
# print(next(gen)) # 结束\nStopIterationyield from - 委托生成器def sub_generator():
yield "a"
yield "b"
def main_generator():
yield 1
yield from sub_generator() # 委托给另一个生成器
yield 2
for item in main_generator():
print(item) # 1, 'a', 'b', 2send() 方法def echo_generator():
while True:
received = yield # 接收外部发送的值
print(f"收到: {received}")
gen = echo_generator()
next(gen) # 启动生成器
gen.send("Hello") # 收到: Hello
gen.send("World") # 收到: Worldthrow() 和 close()gen = count_up_to(5)
print(next(gen)) # 1
gen.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》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。