Python 里有一个超实用的 “内存小帮手”——生成器!它就像一条智能的数据生产线,不会一股脑儿把所有数据都塞给你,而是需要多少生产多少,特别节省内存。无论是处理海量数据,还是实现异步任务,生成器都能大显身手。接下来,就带大家看看它是怎么工作的!
一、生成器是什么?先和列表对比一下 平时我们用列表保存数据,比如 [1, 2, 3, 4, 5] ,所有元素都存在内存里。但如果数据量超大,像包含 100 万个数字的列表,内存可能就 “吃不消” 了。这时候,生成器就派上用场了!生成器不会一次性生成所有数据,而是 按需生成 ,有点像 “挤牙膏”,用多少取多少。 生成器有两种创建方式:生成器函数和生成器表达式,下面咱们分别来看! 二、生成器函数:用 yield “暂停” 和 “继续” 生成器函数和普通函数长得很像,唯一的区别是它用 yield 关键字替代 return 。yield 就像一个 “暂停键”,每次执行到它,函数会暂停并返回一个值,下次调用时从暂停的地方继续执行。 举个例子,我们写一个生成器函数,生成从 1 到 10 的自然数:
def number_generator(): for num in range(1, 11): 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) # 输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]# 生成器表达式,延迟生成数据square_generator = (x ** 2 for x in range(1, 11))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入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!