【Python】迭代器与生成器详解(可迭代对象、定义、实现方式、区别、使用场景)
文章目录
- 1. 可迭代对象
- 1.1 常见的可迭代对象
- 1.2 迭代器和生成器
- 2. 迭代器
- 2.1 定义
- 2.2 原理
- 2.3 特点
- 2.4 示例
- 2.4.1 for语句进行遍历
- 2.4.2 next() 函数进行遍历
- 2.4.3 自定义迭代器
- 2.5 内置迭代器
- 3. 生成器
- 3.1 定义
- 3.2 创建方式
- 3.2.1 生成器表达式
- 3.2.2 生成器函数
- 3.3 特点
- 4. 迭代器和生成器比较
- 4.1 迭代器优势
- 4.2 生成器优势
- 4.2.1 惰性计算
- 4.2.2 无限序列
- 4.2.3 协程与状态管理
- 5. 使用场景
- 5.1 迭代器和生成器选择原则
1. 可迭代对象
- 迭代是 Python 最强大的功能之一,是访问集合元素的一种方式
- 可迭代对象 :可以被循环遍历的对象
1.1 常见的可迭代对象
- 序列类型
列表(list) :是一种可变的序列类型
元组(tuple) :是一种不可变的序列类型
字符串(str) :由字符组成的不可变序列 - 集合类型
集合(set) :无序且元素唯一的集合类型
字典(dict) :以键 - 值对形式存储数据的集合类型。在遍历字典时,默认遍历的是键 - 其他可迭代对象
文件对象 :在 Python 中,打开的文件对象是可迭代的,可以逐行读取文件内容
range() 对象 :用于生成一个不可变的整数序列
1.2 迭代器和生成器
在 Python 中,迭代器(Iterator) 和 生成器(Generator) 都是用于遍历数据的工具,用于处理可迭代对象
2. 迭代器
2.1 定义
迭代器是实现了迭代器协议的对象,是一个可以记住遍历位置的对象
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退
迭代器协议要求对象必须实现两个方法:iter() 和 next()
- iter() :返回迭代器对象本身,通常返回 self。
- next() :返回迭代器的下一个值,如果没有元素则抛出 StopIteration 异常
2.2 原理
迭代器是一种 惰性求值 的机制,它并不一次性生成所有元素,而是在需要时 逐个生成元素 ,这样可以节省内存
当你使用 for 循环遍历一个迭代器时,实际上是在不断调用迭代器的 next() 方法,直到抛出 StopIteration 异常
2.3 特点
- 惰性计算 :按需生成元素,适合处理大数据集
- 一次性使用 :遍历结束后需重新初始化才能再次使用
- 手动控制 :需显式调用 next() 或使用 for 循环
2.4 示例
2.4.1 for语句进行遍历
迭代器对象使用常规 for语句 进行遍历
list = [1, 2, 3, 4]
it = iter(list) # 创建迭代器对象
for x in it:
print(x, end=" ")
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
1 2 3 4Process finished with exit code 0
2.4.2 next() 函数进行遍历
也可以使用 next() 函数 进行遍历
import sys # 引入 sys 模块
list = [1, 2, 3, 4]
it = iter(list) # 创建迭代器对象
while True:
try:
print(next(it))
except StopIteration:
sys.exit()
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
1 2 3 4Process finished with exit code 0
2.4.3 自定义迭代器
示例:生成 0 到 n 的偶数
class TestIterator:
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
value = self.current
self.current += 2
return value
# 使用迭代器
even_iter = TestIterator(6)
for num in even_iter:
print(num) # 输出: 0 2 4
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
0 2 4Process finished with exit code 0
注:
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况;在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代
2.5 内置迭代器
- Python 中的许多内置对象(如列表、元组、字符串等)都可以通过 iter() 函数 转换为迭代器
my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)
print(next(my_iterator)) # 输出: 1
print(next(my_iterator)) # 输出: 2
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
1 2Process finished with exit code 0
3. 生成器
3.1 定义
- 生成器是一种特殊的迭代器,通过 yield 关键字 实现,无需显式定义 iter 和 next
3.2 创建方式
3.2.1 生成器表达式
- 生成器表达式:类似于列表推导式,但使用 圆括号 () 而不是方括号 []
gen_expr = (x for x in range(0, 6, 2))
print(list(gen_expr)) # 输出: [0, 2, 4]
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
[0, 2, 4]Process finished with exit code 0
3.2.2 生成器函数
- 生成器函数: 使用 def 定义,包含 yield 关键字 的函数
- 当函数被调用时,它不会立即执行,而是返回一个生成器对象
- 每次调用生成器的 next() 方法时,函数会从上次暂停的位置继续执行,直到遇到下一个 yield 语句或函数结束
# 生成器函数:生成 0 到 n 的偶数
def test_generator(n):
current = 0
while current < n:
yield current
current += 2
# 使用生成器
gen = test_generator(6)
for num in gen:
print(num) # 输出: 0 2 4
# test_generator 是一个生成器函数,yield 关键字将函数转换为生成器。
# 每次调用 __next__() 方法时,函数会执行到 yield 语句,返回 yield 后面的值,并暂停执行,下次调用时从暂停的位置继续执行
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
0 2 4Process finished with exit code 0
3.3 特点
- 简洁性 :自动实现迭代器协议,代码更简洁
- 惰性计算 :按需生成元素,节省内存
- 状态保存 :每次 yield 暂停执行,下次从暂停位置继续
4. 迭代器和生成器比较
\ | 迭代器 | 生成器 |
---|---|---|
实现方式 | 需手动定义 iter 和 next | 使用 yield 或生成器表达式 |
代码复杂度 | 代码较多 | 代码更简洁 |
内存占用 | 通常需预先生成数据 | 惰性生成,节省内存 |
适用场景 | 需要自定义复杂遍历逻辑 | 快速实现按需生成数据 |
性能 | 取决于实现逻辑 | 通常更高(惰性计算优化) |
4.1 迭代器优势
- 需要 完全控制迭代逻辑 (如自定义遍历顺序)
- 需要 复用迭代器对象 (生成器通常只能遍历一次)
# 自定义树结构的遍历
class TreeNode:
def __init__(self, value):
self.value = value
self.children = []
class TreeIterator:
def __init__(self, root):
self.stack = [root]
def __iter__(self):
return self
def __next__(self):
if not self.stack:
raise StopIteration
node = self.stack.pop()
self.stack.extend(node.children[::-1]) # 逆序压栈,实现前序遍历
return node.value
# 使用迭代器遍历树
root = TreeNode(1)
root.children = [TreeNode(2), TreeNode(3)]
for value in TreeIterator(root):
print(value) # 输出: 1 2 3
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
1 2 3Process finished with exit code 0
4.2 生成器优势
4.2.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("data.txt"):
process(line) # 假设 process 是处理函数
4.2.2 无限序列
- 生成器可以表示无限序列,如斐波那契数列
# 使用生成器函数生成斐波那契数列,并将该数列的前 n(这里 n 为 10)项依次打印输出
# !/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0 # 初始化三个变量
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print(next(f), end=" ")
except StopIteration:
sys.exit()
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
0 1 1 2 3 5 8 13 21 34 55Process finished with exit code 0
4.2.3 协程与状态管理
- 生成器可通过 接收外部数据 send() ,用于协程编程
def coroutine():
while True:
received = yield
print(f"Received: {received}")
co = coroutine()
next(co) # 启动生成器
co.send("Hello") # 输出: Received: Hello
输出:
D:\PycharmProjects\pythonProject.venv\Scripts\python.exe
D:\PycharmProjects\pythonProject-test.py
Received: HelloProcess finished with exit code 0
5. 使用场景
- 大数据处理 send():当处理大型数据集时,使用迭代器和生成器可以避免一次性将所有数据加载到内存中,提高程序的性能和内存使用效率
- 无限序列生成 send():生成器可以方便地生成无限序列,如斐波那契数列等,只需在生成器函数中使用循环和 yield 语句即可
5.1 迭代器和生成器选择原则
迭代器:适合需要精细控制遍历逻辑的场景,需手动实现接口
生成器:适合快速实现惰性计算、处理大数据或无限序列,代码简洁高效
选择原则:
- 优先使用生成器(更简洁,适合大多数场景)
- 需要复杂遍历逻辑或复用迭代器时,使用迭代器
如有其他问题,欢迎各位大佬指正~