Python 生成器与 yield 关键字实战:5 个节省内存的高级用法与性能优化技巧

Python 生成器与 yield 关键字实战:5 个节省内存的高级用法与性能优化技巧

在日常 Python 开发中,我们经常需要处理大量数据。如果把所有数据一次性加载到内存中,很容易导致内存溢出。生成器(Generator)正是解决这个问题的利器。

什么是生成器?

生成器是一种特殊的迭代器,它使用 yield 关键字按需产生值,而不是一次性生成所有结果。与普通函数不同,生成器函数在每次 yield 后会暂停执行,下次调用时从暂停的位置继续。

  1. 基础用法:读取大文件逐行处理

假设我们要分析一个 10GB 的日志文件,如果用列表存储所有行,内存直接爆掉。使用生成器可以逐行读取,内存占用始终保持在最低水平:

def read_large_file(file_path):

with open(file_path, 'r') as f:

for line in f:

yield line.strip()

for line in read_large_file('access.log'):

if 'ERROR' in line:

print(line)

这种方式的优势在于,无论文件有多大,内存中同时只存在一行数据。

  1. 生成器表达式:简洁的数据管道

生成器表达式用类似列表推导式的语法,但返回的是生成器对象而非列表,内存占用微乎其微:

numbers = range(10000000)

squared_even = (x * x for x in numbers if x % 2 == 0)

for val in squared_even:

if val > 1000:

break

print(val)

对比使用方括号的列表推导式,圆括号的生成器表达式不会预先创建整个列表,只在实际迭代时才计算每个值。

  1. yield from:组合多个生成器

Python 3.3 引入了 yield from 语法,可以将多个生成器串联起来,形成数据管道:

def read_config():

yield 'debug=True'

yield 'port=8080'

def read_data():

yield 'row1'

yield 'row2'

def pipeline():

yield from read_config()

yield '---'

yield from read_data()

for item in pipeline():

print(item)

这种模式非常适合构建 ETL 数据管道,每个阶段独立维护自己的逻辑。

  1. 生成器实现无限序列:斐波那契数列

生成器可以表示无限序列,因为值是按需计算的,不会占用无限内存:

def fibonacci():

a, b = 0, 1

while True:

yield a

a, b = b, a + b

fib = fibonacci()

for _ in range(10):

print(next(fib))

配合 itertools.islice 可以安全地取前 N 项,不用担心无限循环问题。

  1. 协程与生成器:send 方法实现双向通信

生成器不仅能产出值,还能通过 send 方法接收外部传入的数据,这是 Python 早期协程的基础:

def accumulator():

total = 0

while True:

value = yield total

if value is not None:

total += value

acc = accumulator()

next(acc) # 启动生成器

print(acc.send(10)) # 输出 10

print(acc.send(20)) # 输出 30

print(acc.send(5)) # 输出 35

这种模式可以用于实现流式计算、实时统计等场景。

  1. 性能对比:生成器 vs 列表

我们用一个简单的实验来量化生成器的内存优势:

import sys

import time

data = list(range(1000000))

列表方式

list_result = x \* 2 for x in data

print(f'列表占用内存: {sys.getsizeof(list_result)} 字节')

生成器方式

gen_result = (x * 2 for x in data)

print(f'生成器占用内存: {sys.getsizeof(gen_result)} 字节')

典型结果是列表占用约 8MB,而生成器仅占用不到 200 字节,差距超过 40000 倍。

  1. 实战案例:生成器实现生产者消费者模式

import threading

import queue

import time

def producer(q, n):

for i in range(n):

q.put(i)

time.sleep(0.1)

q.put(None) # 结束信号

def consumer(q):

while True:

item = q.get()

if item is None:

break

print(f'处理: {item}')

q = queue.Queue(maxsize=10)

t1 = threading.Thread(target=producer, args=(q, 20))

t2 = threading.Thread(target=consumer, args=(q,))

t1.start()

t2.start()

t1.join()

t2.join()

虽然这个例子用的是 queue,但生成器配合 yield 同样可以实现类似的生产者消费者模式,而且代码更加简洁优雅。

总结

生成器是 Python 中最被低估的特性之一。它的核心价值在于延迟计算和内存高效,特别适合以下场景:

  1. 处理大规模数据集,避免内存溢出

  2. 构建数据管道,实现流式处理

  3. 表示无限序列,按需生成

  4. 替代回调,简化异步代码逻辑

下次遇到需要处理大量数据的场景时,先想想能不能用生成器来优化,往往会有意想不到的效果。

相关推荐
浮尘笔记12 小时前
Go实现大文件异步流式采集引擎
开发语言·后端·golang
winfredzhang12 小时前
Python + wxPython + SQLite 实战:开发一个本地 Python 项目一键启动管理工具
python·sqlite·bat·截图·claudecode·codingliteplan
yugi98783812 小时前
基于C#实现数字识别率的OCR方案
开发语言·c#·ocr
星越华夏12 小时前
python中四种获取文件后缀名的方法
开发语言·python
lunzi_082612 小时前
【学习笔记】《Python编程 从入门到实践》第9章:类、继承、组合与面向对象编程
笔记·python·学习
大蚂蚁2号12 小时前
本地批量音视频转文本免费工具
python·音视频·开源软件
copyer_xyf12 小时前
FastAPI 项目骨架搭建
前端·后端·python
十正12 小时前
aiohttp.TCPConnector 连接池原理详解
网络·python·tcp·aiohttp
LoserChaser12 小时前
Flask 文件上传服务器 - 知识点总结
服务器·python·flask
cd9888012 小时前
2026年,哪家电销机器人定制更灵活?
python