生成器函数返回迭代器对象而非列表,调用时立即返回generator,每次yield挂起并保存状态,仅按需计算单个值,内存占用极小;生成器表达式同理,但不可索引、不可重复遍历。

生成器函数返回的是迭代器对象,不是一次性列表
调用 def 定义的生成器函数(含 yield)时,Python 不执行函数体,而是立即返回一个 generator 对象。这个对象是迭代器,支持 __next__(),但内部不保存全部结果。
对比普通函数:
- 返回
list的函数:必须在内存中构造完整列表,比如[x**2 for x in range(1000000)]会立刻占用数百 MB - 生成器函数:每次只计算并产出一个值,例如
def squares(n): yield from (i**2 for i in range(n)),调用时几乎不占额外内存
yield 让函数挂起并保留局部状态
每次遇到 yield,函数暂停执行,把值交还给调用方,同时冻结当前栈帧(包括局部变量、指令指针等)。下次调用 __next__() 时从中断处继续,而不是重新开始。
这意味着:
立即学习“Python免费学习笔记(深入)”;
- 不需要为整个序列分配连续内存空间
- 递归或复杂状态(如文件读取位置、计数器)可自然保留在生成器内部
- 若生成器未被完全消费(比如只取前 5 个值),后续逻辑不会触发,对应计算被跳过
生成器表达式比列表推导式更省内存
(x**2 for x in range(10**6)) 是生成器表达式,而 [x**2 for x in range(10**6)] 是列表推导式。前者本质是匿名生成器函数调用,后者直接构建对象列表。
关键差异:
- 生成器表达式不支持索引、
len()、重复遍历;必须用for或显式next() - 若需多次使用结果,生成器只能消费一次,强行转成
list()就失去内存优势 - 嵌套生成器(如
(y for x in data for y in x))仍保持单次流式处理,无中间容器
注意生成器无法回退和随机访问
生成器是单向迭代器,没有 seek() 或 reset() 方法。一旦调用 next() 走过某个值,它就从内存中“消失”了(除非你额外缓存)。
容易踩的坑:
- 误以为
list(gen)后还能继续用gen—— 实际上已耗尽,再调用next(gen)会抛StopIteration - 在
for循环中意外中断(如break或异常),可能导致资源未清理(建议用try/finally或上下文管理器封装) - 调试时打印
gen只看到,看不到内容,得用list(gen)或逐个next()查看
真正省内存的前提,是你别把它一次性全展开。只要保持“按需产出、即产即用”的节奏,生成器的轻量级状态机机制才能发挥效果。










