目录
一、生成器介绍
生成器是Python中一种特殊的迭代器,关键字是yield,
它允许你按需生成值,而不是一次性计算并存储所有值。这种"惰性计算"的特性使得生成器在处理大数据集或无限序列时非常高效。
1.1 生成器与迭代器的关系
生成器是一种特殊的迭代器,具有迭代器的所有特性,但更简洁。生成器自动实现了迭代器协议(即__iter__()和__next__()方法),并且状态挂起和恢复是自动的。
迭代器是一个可以记住遍历位置的对象,它从集合的第一个元素开始访问,直到所有元素被访问完结束,只能往前不会后退。生成器是使用yield表达式来生成值的函数,每次调用next()时,生成器会从上次yield的位置继续执行,直到遇到yield或return(包括函数结束)为止。
生成器是迭代器的一种,但迭代器不一定是生成器。
- 迭代器可以通过实现类的__iter__和__next__方法来创建
- 生成器通过函数和yield来创建。
1.2 生成器与return比较
- 普通函数使用
return
返回结果后,其执行状态就会被销毁。 - 生成器使用
yield
关键字,在返回值的同时会保存当前执行状态,下次调用时可以从上次暂停的地方继续执行。
通俗的说,yield就是和return一样执行到该位置时返回变量值,但函数不会结束退出,而是暂停在这个位置挂起任务,等待下一次next()调用时,从暂停的位置继续执行。
二、创建生成器
方法1: 生成器函数
使用yield
关键字代替return
的函数就是生成器函数:
def simple_generator():
yield 1
yield 2
yield 3
# 使用生成器
gen = simple_generator()
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
print(next(gen)) # 输出: 3
方法2: 生成器表达式
类似列表推导式,但使用圆括号:
# 列表推导式 - 立即计算所有值
squares_list = [x*x for x in range(5)] # [0, 1, 4, 9, 16]
# 生成器表达式 - 按需生成值
squares_gen = (x*x for x in range(5))
print(next(squares_gen)) # 输出: 0
print(next(squares_gen)) # 输出: 1
三、生成器的实际应用场景
3.1 处理大型文件
def read_large_file(file_path):
"""逐行读取大文件,避免内存溢出"""
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
# 使用生成器处理GB级文件
for line in read_large_file('huge_file.txt'):
process_line(line) # 每次只处理一行,不占用大量内存
3.2 生成无限序列
def fibonacci():
"""生成无限斐波那契数列"""
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 获取前10个斐波那契数
fib_gen = fibonacci()
first_10 = [next(fib_gen) for _ in range(10)]
print(first_10) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
3.3 数据管道处理
def numbers():
for i in range(10):
yield i
def square(nums):
for num in nums:
yield num ** 2
def even_filter(nums):
for num in nums:
if num % 2 == 0:
yield num
# 构建数据处理管道
result = even_filter(square(numbers()))
print(list(result)) # [0, 4, 16, 36, 64]
四、生成器的高级用法
4.1 使用send()方法传递值
def generator_with_send():
value = yield "开始"
while True:
value = yield f"收到: {value}"
gen = generator_with_send()
print(next(gen)) # 输出: "开始"
print(gen.send("你好")) # 输出: "收到: 你好"
print(gen.send("世界")) # 输出: "收到: 世界"
4.2 生成器委托(yield from)
def sub_generator():
yield from range(3)
yield from ['a', 'b', 'c']
for item in sub_generator():
print(item) # 输出: 0, 1, 2, 'a', 'b', 'c'
五、生成器的特点
优势:
内存效率:一次只产生一个值,不占用大量内存
惰性计算:需要时才计算,避免不必要的运算
代码简洁:用简洁的语法表达复杂的迭代逻辑
流水线处理:可以构建高效的数据处理管道
缺点:
生成器只能迭代一次,迭代完后需要重新创建
不适合需要随机访问的场景
调试可能比普通函数复杂
总结
生成器是Python中强大而高效的工具,特别适合处理大数据流、构建数据处理管道和创建无限序列。通过掌握生成器,你可以编写出更加内存友好和Pythonic的代码。