生成器深入
生成器深入
生成器是Python中一种特殊的迭代器,它使用 yield 关键字返回值,而不是 return。生成器的核心优势在于惰性求值——只在需要时才计算下一个值,极大地节省内存。
yield 的基本用法
def countdown(n):
"""倒计时生成器"""
print("开始倒计时!")
while n > 0:
yield n
n -= 1
print("发射!")
for num in countdown(5):
print(num)
# 输出: 5, 4, 3, 2, 1, 发射!
yield 会暂停函数执行并返回值,下次迭代时从上次暂停的位置继续。
生成器表达式
类似列表推导式,但使用圆括号:
# 列表推导式 - 一次性创建所有元素
squares_list = [x**2 for x in range(1000000)]
# 生成器表达式 - 按需生成
squares_gen = (x**2 for x in range(1000000))
print(type(squares_gen)) # <class 'generator'>
yield from 语法
yield from 用于将一个可迭代对象的值逐个yield出来:
def flatten(nested_list):
"""递归展平嵌套列表"""
for item in nested_list:
if isinstance(item, list):
yield from flatten(item) # 委托给子生成器
else:
yield item
nested = [1, [2, 3], [4, [5, 6]], 7]
print(list(flatten(nested)))
# [1, 2, 3, 4, 5, 6, 7]
send 方法
生成器可以通过 send() 方法接收外部传入的值:
def accumulator():
"""累加器生成器"""
total = 0
while True:
value = yield total
if value is None:
break
total += value
acc = accumulator()
next(acc) # 启动生成器
print(acc.send(10)) # 10
print(acc.send(20)) # 30
print(acc.send(5)) # 35
生成器的状态
生成器有三种状态:GEN_CREATED(已创建)、GEN_SUSPENDED(挂起)、GEN_CLOSED(已关闭):
def simple_gen():
yield 1
yield 2
yield 3
gen = simple_gen()
print(gen.gi_code.co_flags) # 生成器状态
# 使用 inspect 模块检查状态
import inspect
print(inspect.getgeneratorstate(gen)) # GEN_CREATED
next(gen)
print(inspect.getgeneratorstate(gen)) # GEN_SUSPENDED
异常处理
生成器可以捕获外部抛入的异常:
def generator_with_exception():
try:
while True:
value = yield
print(f"收到: {value}")
except ValueError as e:
print(f"捕获异常: {e}")
finally:
print("生成器关闭")
gen = generator_with_exception()
next(gen)
gen.send(10) # 收到: 10
gen.throw(ValueError, "测试错误") # 捕获异常: 测试错误
无限序列
生成器天然适合表示无限序列:
def fibonacci():
"""无限斐波那契数列"""
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 使用 islice 获取前10个
from itertools import islice
fib = fibonacci()
print(list(islice(fib, 10)))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
实战:管道式数据处理
def read_data(filename):
with open(filename) as f:
for line in f:
yield line.strip()
def filter_lines(lines, keyword):
for line in lines:
if keyword in line:
yield line
def transform(lines):
for line in lines:
yield line.upper()
# 管道组合
data = read_data("data.txt")
filtered = filter_lines(data, "error")
uppercased = transform(filtered)
for line in uppercased:
print(line)
生成器是Python中处理大数据和流式处理的利器,掌握它能让你写出更高效的代码。