page contents

揭秘 Python 生成器:内存友好的 “数据生产线”

Python 里有一个超实用的 “内存小帮手”——生成器!它就像一条智能的数据生产线,不会一股脑儿把所有数据都塞给你,而是需要多少生产多少,特别节省内存。无论是处理海量数据,还是实现异步任务,生成器都能大显身手。接下来,就带大家看看它是怎么工作的!

attachments-2025-05-BwNfQUun6823f77ee794b.jpgPython 里有一个超实用的 “内存小帮手”——生成器!它就像一条智能的数据生产线,不会一股脑儿把所有数据都塞给你,而是需要多少生产多少,特别节省内存。无论是处理海量数据,还是实现异步任务,生成器都能大显身手。接下来,就带大家看看它是怎么工作的!

 一、生成器是什么?先和列表对比一下 平时我们用列表保存数据,比如 [1, 2, 3, 4, 5] ,所有元素都存在内存里。但如果数据量超大,像包含 100 万个数字的列表,内存可能就 “吃不消” 了。这时候,生成器就派上用场了!生成器不会一次性生成所有数据,而是 按需生成 ,有点像 “挤牙膏”,用多少取多少。 生成器有两种创建方式:生成器函数生成器表达式,下面咱们分别来看! 二、生成器函数:用 yield “暂停” 和 “继续” 生成器函数和普通函数长得很像,唯一的区别是它用 yield 关键字替代 return 。yield 就像一个 “暂停键”,每次执行到它,函数会暂停并返回一个值,下次调用时从暂停的地方继续执行。 举个例子,我们写一个生成器函数,生成从 1 到 10 的自然数

def number_generator():    for num in range(111):        yield num  # 使用yield返回值,函数变为生成器函数gen = number_generator()  # 创建生成器对象for _ in range(3):    print(next(gen))  # 输出:1 2 3

代码解释: 1.number_generator 函数里的 yield num 让函数变成了生成器。 2.next(gen) 用于 “唤醒” 生成器,获取下一个值。每调用一次 next ,生成器从上次 yield 的地方继续执行。 小贴士:当生成器没有更多数据可生成时,调用 next 会抛出 StopIteration 异常。一般用 for 循环迭代生成器,它会自动处理这个异常。三、生成器表达式:列表推导式的 “兄弟 生成器表达式和列表推导式语法很像,只不过把列表推导式的方括号 [] 换成圆括号 () 。但它们的工作方式完全不同:列表推导式会立即生成完整列表,而生成器表达式不会立即计算数据,只有在需要时才生成。 比如,生成 1 到 10 的平方数:

# 列表推导式,立即生成列表square_list = [x ** 2 for x in range(1, 11)]print(square_list)  # 输出:[149162536496481100]# 生成器表达式,延迟生成数据square_generator = (x ** 2 for x in range(111))print(next(square_generator))  # 输出:1print(next(square_generator))  # 输出:4

从内存占用来看,如果要生成 100 万个数字的平方,列表推导式会一次性占用大量内存,而生成器表达式几乎不占用额外内存,因为它只有在调用 next 时才计算数据。 
四、生成器的实际应用场景 1. 处理大文件 读取超大文件时,用生成器可以一行一行读取,避免一次性把文件内容全塞进内存。

def read_large_file(file_path):    with open(file_path, 'r'as file:        for line in file:            yield line  # 每次返回一行内容file_gen = read_large_file('large_file.txt')for _ in range(5):    print(next(file_gen).strip())  # 输出文件的前5行

2. 无限数据流 生成器可以模拟无限数据流,比如生成无限的随机数序列:

import randomdef infinite_random_generator():    while True:        yield random.random()  # 无限生成随机数rand_gen = infinite_random_generator()print(next(rand_gen))  # 输出一个随机数

五、生成器的进阶玩法:生成器的 send 和 throw
 除了 next 方法,生成器还有 send 和 throw 方法。send 可以在唤醒生成器的同时,向生成器内部传入数据;throw 则用于在生成器内部抛出异常。

def counter():    count = 0    while True:        increment = yield count  # yield暂停并返回count,同时接收外部传入的值        if increment is None:            increment = 1        count += incrementgen = counter()print(next(gen))  # 输出:0print(gen.send(5))  # 传入5,输出:5print(gen.send(3))  # 传入3,输出:8

这里 yield count 不仅返回 count 的值,还能通过 send 接收外部传入的 increment ,更新 count 的值。六、使用生成器的注意事项 1.生成器只能迭代一次:一旦生成器数据被全部迭代完,再次调用 next 会报错。如果需要重复使用数据,建议重新创建生成器对象。 2.调试困难:因为生成器的执行是 “暂停 - 继续” 模式,调试时可能不太直观。可以在 yield 附近加 print 语句辅助排查问题。 3.函数式编程结合:生成器常和 map、filter 等函数式工具搭配使用,能写出简洁又高效的代码。 
七、练习题 
1.用生成器函数实现一个斐波那契数列生成器,能无限生成斐波那契数。 2.有一个包含 10 万个随机整数的文件 random_numbers.txt ,用生成器表达式读取文件,计算所有数字的平均值(避免一次性读取所有数据)。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2025-05-14 09:53
  • 阅读 ( 55 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1303 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2136 文章
  3. Pack 1303 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章