Sunday面试指南

Python 迭代器和生成器有什么区别?yield 为什么能节省内存?

🧑‍💻 面试官:Python 生成器和普通列表有什么区别?

🙋‍♂️ 我:生成器更省内存,因为不会一次生成所有数据。

🧑‍💻 面试官:如果马上 list(generator),还保留这个优势吗?

🙋‍♂️ 我:那又把所有结果放进列表了。

🧑‍💻 面试官:生成器消费完,再遍历一次会从头开始吗?处理中打开的文件谁负责关闭?

生成器保存的是一个可继续执行的过程;按需取值能省掉结果堆积,但不自动保证无限复用和资源安全。

面试速答(60 秒版)

生成器按迭代请求逐步执行,遇到 yield 返回一个值并暂停,下一次继续时保留执行位置和局部状态。

它不必提前把所有结果放进列表,因此适合按需处理较大数据。但如果最后立即转换成列表,结果仍会全部进入内存;输入或内部缓存也可能继续占空间。

同一个生成器对象通常是一次性消费过程,耗尽后不会自动从头开始,需要重新创建。yield 不等于后台并行,也不等于每次都会异步等待。

涉及文件、连接或提前停止时,要明确清理责任;异步数据则使用对应异步迭代机制,不能只换一个 yield 就变成异步I/O。

生成器按请求推进、yield暂停保存状态,耗尽后需要重新创建

知识点详解:一个暂停的函数,怎样逐次交出结果

普通列表先备货,生成器按需求往下做

假设你要逐条转换一份大数据。返回列表的函数会先收集全部转换结果,完成后再交给调用方。

生成器则可以先交出第一条。调用方处理完再请求下一条,函数从暂停位置继续。它保存的是执行过程,不是每次重新调用函数从第一行开始。

这让消费和生产节奏更容易配合,但前提是链路没有在中间又把全部结果收集起来。输入已经是一个巨大列表时,那份输入本身也没有因为 yield 消失。

同一个对象,消费完不会重新开始

下面是同一按需取值机制的 Python 和 TypeScript 生成器。两种语言的结束协议不同,但这个示例都展示同一个对象的一次性消费。

Python

def squares(n):
    for i in range(n):
        yield i * i

values = squares(3)
print(list(values))  # [0, 1, 4]
print(list(values))  # []

TypeScript

function* squares(n: number) {
  for (let i = 0; i < n; i++) yield i * i;
}
const values = squares(3);
console.log([...values]); // [0, 1, 4]
console.log([...values]); // []

需要重新遍历,就再次调用 squares 创建新的对象,或者明确缓存结果。这里转换成列表只是为了打印演示,不是大数据处理的推荐收集方式。

yield 是暂停点,不是并行开关

普通生成器在调用方请求时推进。它暂停期间不会自动在后台继续生产,函数中的大同步计算也不会因为含有 yield 就被系统拆成并行任务。

Python 的 next 在耗尽时通过 StopIteration 结束;JavaScript 迭代结果用 done 表示结束。for 语句帮你处理协议,所以平时不必手工捕获每次结束。

读取异步来源时,可以使用异步生成器和 async for 等机制。但是否真的等待 I/O,仍取决于内部的 await 和具体接口,而不是关键词本身。

提前不读了,清理不能靠猜

生成器内部可能拿着文件、网络连接或较大的对象引用。只取几条就停止时,要检查资源什么时候释放。

可以在生成器中用 try/finally 表达清理,再由调用方按语言和接口明确关闭。Python 的普通 for 提前 break,不承诺自动替你调用生成器 close;不要把垃圾回收时机当确定的资源生命周期。

还要处理消费中的异常。数据库查询是按页拉取还是一次拿全,游标是否已经缓存全部数据,都要核对实际实现。

真正的验收不是只证明返回了 Generator,而是观察数据何时产生、内存如何增长、停止后资源是否及时收回。

本题机制参考:Python:Functional Programming HOWTO、MDN:function*。

面试官继续追问

生成器一定比列表快吗?

不一定。它主要提供按需执行和减少结果堆积的机会,逐项调度也有成本,要按消费方式测。

生成器可以无限次遍历吗?

同一个耗尽对象通常不能重新开始。重新创建过程与缓存结果是两种不同方案。

Python for 提前 break 会自动关闭生成器吗?

不能这样保证。需要确定性清理时明确管理close或外部资源,不依赖垃圾回收。

面试速记卡

  • yield:返回一项并暂停,保存执行位置。
  • 内存:不提前收集全部结果,但输入与缓存仍有成本。
  • 消费:同一对象耗尽后不会自动重启。
  • 执行:普通生成器不是后台线程或异步I/O。
  • 清理:提前停止和异常时明确关闭责任。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历