2025-04-11    2025-04-11    999 字  2 分钟

在 Python 中,yield 关键字用于定义生成器函数(Generator Function),它的核心作用是实现惰性计算(Lazy Evaluation),允许函数在执行过程中暂停并保存状态,后续可以恢复执行。以下是 yield 的详细作用和典型应用场景:


一、yield 的核心作用

1. 生成器函数

  • yield 将普通函数转换为生成器函数,调用生成器函数时返回一个生成器对象(Generator Object),而不是直接计算结果。
  • 生成器对象支持迭代(for 循环或 next()),每次迭代执行到 yield 时返回一个值,并暂停函数状态,下次迭代从暂停处继续执行。

2. 惰性计算(按需生成数据)

  • 生成器不会一次性生成所有数据,而是逐次生成,适合处理大数据集或无限序列,避免内存溢出(OOM)。

3. 状态保持

  • 生成器函数会记住上次执行的位置和局部变量,每次调用 next() 时恢复执行上下文。

二、yieldreturn 的对比

特性 yield return
返回值类型 生成器对象(可迭代) 直接返回结果
执行方式 多次执行,每次返回一个值 执行一次后终止
内存占用 低(逐个生成数据) 高(需存储所有结果)
适用场景 大数据、流处理、无限序列 小规模、一次性计算结果

三、典型使用场景

1. 处理大规模数据

1
2
3
4
5
6
7
8
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)  # 处理每一行

2. 生成无限序列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def infinite_sequence():
    num = 0
    while True:
        yield num
        num += 1

# 逐个生成自然数(不会内存溢出)
gen = infinite_sequence()
print(next(gen))  # 0
print(next(gen))  # 1

3. 实现协程(Coroutine)

通过 yieldsend() 实现双向通信:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def coroutine():
    while True:
        value = yield  # 接收外部传入的值
        print(f"Received: {value}")

# 启动协程
c = coroutine()
next(c)          # 初始化生成器(执行到第一个 yield)
c.send("Hello")  # 输出:Received: Hello
c.send(42)       # 输出:Received: 42

四、yield from 简化嵌套生成器

Python 3.3+ 引入 yield from,用于委托生成器:

1
2
3
4
5
6
7
8
def generator1():
    yield from range(3)  # 委托给 range(3)

def generator2():
    yield from generator1()  # 委托给 generator1

for num in generator2():
    print(num)  # 输出 0, 1, 2

五、注意事项

  1. 生成器只能遍历一次

    生成器对象迭代结束后无法重复使用,需重新创建生成器。

  2. 生成器与列表的转换

    可通过 list(generator) 将生成器结果转为列表(但会丢失惰性计算优势)。

  3. 性能权衡

    生成器适合内存敏感场景,但频繁调用 next() 可能增加 CPU 开销。


六、总结

  • 核心价值yield 通过惰性计算和状态保持,实现内存高效的数据流处理。
  • 适用场景
    • 处理大文件或数据库查询结果(避免内存溢出)。
    • 生成无限序列(如斐波那契数列)。
    • 实现协程和异步编程模式。
  • 替代方案
    • 小数据用 return + 列表。
    • 高性能场景可结合 itertools 模块优化。