广告
您当前的位置: 首页 >  技术 >  Python

Python 深入浅出:生成器与 yield 关键字的妙用

作者:XiaoZhang 时间:2026-06-27 阅读数:7人阅读

在处理大数据集、日志分析或无限流数据时,我们经常面临一个尴尬的境地:一次性将所有数据加载到内存中会导致程序崩溃,而逐个处理又会使代码变得臃肿。

Python 引入的生成器(Generators)yield 关键字,提供了一种优雅的“惰性求值(Lazy Evaluation)”解决方案。它能以接近零的内存开销,处理无限大的数据集。本文将带您由浅入深,领略生成器与 yield 的艺术。


一、 什么是生成器?

在 Python 中,生成器是一种特殊的迭代器。它不会一次性把所有元素都计算出来放进内存,而是在循环迭代时,需要一个、计算一个

传统列表 vs. 生成器表达式

  • 列表推导式:使用方括号 [],立即计算并生成完整的列表。
  • 生成器表达式:使用圆括号 (),返回一个生成器对象,不立即计算。
import sys

# 1. 列表推导式(占用大量内存)
my_list = [i for i in range(1000000)]
print(f"列表占用内存: {sys.getsizeof(my_list)} 字节")  # 约 8MB

# 2. 生成器表达式(几乎不占内存)
my_gen = (i for i in range(1000000))
print(f"生成器占用内存: {sys.getsizeof(my_gen)} 字节")  # 仅约 100 字节!

二、 核心驱动力:yield 关键字

除了用圆括号定义简单的生成器,我们还可以通过在函数中使用 yield 关键字,来编写功能强大的生成器函数。

1. yieldreturn 的根本区别

  • return:结束函数执行,并返回一个值。下一次调用函数时,它会从头开始运行。
  • yield:暂时挂起(Pause)函数状态,向调用者返回一个值,并保留当前所有的局部变量和执行进度。当下一次调用 next() 或迭代时,函数会从挂起的地方继续运行。

2. 编写您的第一个生成器函数

def count_down(num):
    print("开始倒计时...")
    while num > 0:
        yield num  # 挂起并返回值
        num -= 1
    print("倒计时结束!")

# 获取生成器对象
gen = count_down(3)

# 逐步获取值
print(next(gen))  # 输出: 开始倒计时... 然后返回 3
print(next(gen))  # 恢复执行,输出: 2
print(next(gen))  # 恢复执行,输出: 1
# 再次调用 next(gen) 会抛出 StopIteration 异常,提示迭代结束

通常我们不会手动去调 next(),而是直接使用 for 循环来迭代它,Python 会在后台自动处理 StopIteration

for value in count_down(3):
    print(value)

三、 实战案例:惰性读取海量日志文件

假设服务器上有一个 10GB 大小的日志文件,如果您直接使用 file.readlines(),会导致服务器内存瞬间爆仓。我们可以使用生成器来实现按需读取:

def read_large_file(file_path):
    with open(file_path, "r", encoding="utf-8") as file:
        for line in file:
            # 每次只读取并产生一行,处理完这一行后才读取下一行
            yield line

# 处理日志
for log_line in read_large_file("production.log"):
    if "ERROR" in log_line:
        print("发现错误日志:", log_line.strip())

在这个例子中,无论日志文件有多大,我们的程序在运行过程中永远只占用读取单行日志所需的微量内存


四、 总结

  1. 内存极其友好:生成器在时间复杂度上与普通循环一致,但在空间复杂度上实现了从 $O(N)$ 到 $O(1)$ 的降维打击。
  2. 惰性计算:只在需要时计算,非常适合处理网络流、无限序列或庞大的本地文件。
  3. 保留上下文yield 能够在保持函数执行状态的前提下进行数据交换,是 Python 协程和异步编程(asyncio)的重要底层基石。

希望您在下次编写涉及大数据处理的代码时,能够自然地用起 yield,写出更高效的 Python 代码!

本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。

评论交流 (0)

正在加载评论...
头像

XiaoZhang

当你还撑不起你的梦想时,就要去奋斗。如果缘分安排我们相遇,请不要让她擦肩和过。我们一起奋斗!

微信