如何在 Python 中使用生成器(yield 语句)

了解如何用 Python 编写生成器。了解yield关键字、惰性求值、内存优化,并将生成器与列表结构进行比较。

在编辑器中尝试此解决方案

概述

当处理大量数据集、日志文件或无限数据流时,同时将所有元素加载到内存中(例如返回一个大列表)很容易耗尽系统 RAM 并使应用程序崩溃。 Python 提供了一个出色的、节省内存的解决方案:生成器。

生成器是一种特殊类型的函数,它返回惰性迭代器。生成器不是一次计算所有值并返回它们,而是根据请求逐一生成值。主要区别在于“yield”声明。当生成器函数调用“yield”时,它会暂停其执行状态(变量、指​​令指针)并返回生成的值。当请求下一个值时,该函数将从暂停处准确恢复。

由于生成器计算是延迟执行的,因此无论数据集大小如何,它们都使用几乎为零的内存。 Python 还支持生成器表达式,它使用括号语法“(x for x in data)”来创建轻量级内联生成器,而无需声明完整函数。

代码和执行输出

该脚本演示了使用生成器函数以及yield 语句和生成器表达式来生成序列。

generators_demo.py
在编辑器中尝试
# 1. Generator function using yield
def count_up_to(limit):
    count = 1
    while count <= limit:
        yield count
        count += 1

# Instantiating the generator
counter = count_up_to(3)
print("Memory safe generator instantiated.")

# Fetching values manually
print("Next 1:", next(counter))
print("Next 2:", next(counter))
print("Next 3:", next(counter))

# 2. Iterating with a for loop (automatically handles StopIteration)
print("\n--- Looping over generator ---")
for num in count_up_to(4):
    print("Num:", num)

# 3. Generator expression (Shorthand syntax)
squares_gen = (x**2 for x in range(1, 4))
print("\nGenerator expression elements:")
print(list(squares_gen)) # Cast to list to print all elements
端子输出
Memory safe generator instantiated.
Next 1: 1
Next 2: 2
Next 3: 3

--- Looping over generator ---
Num: 1
Num: 2
Num: 3
Num: 4

Generator expression elements:
[1, 4, 9]

逐步实施

  • 使用标准 def 关键字定义函数。
  • 使用yield 关键字而不是return 将yield 值返回到迭代器流。
  • 使用 for 循环迭代生成器或调用内置的 next(gen) 函数来提取值。
  • 使用生成器表达式(使用括号)进行简单的内联惰性转换。

常见问题解答

与列表相比,生成器的主要优点是什么?

内存效率。列表同时将所有元素存储在 RAM 中,而生成器则根据需要逐一生成项目,从而允许您处理大于系统总内存的数据集。

当生成器用完物品时会发生什么?

Python 引发 StopIteration 异常。 for 循环会自动捕获此异常以正常退出循环,但在耗尽的生成器上手动调用 next() 将引发异常。

相关主题

推荐的 Python 资源

通过相关的交互式教程、备忘单和代码比较来扩展您的知识。