with语句能强制触发关闭逻辑,而手动关闭在异常时大概率失效;它通过__exit__方法同步执行close()和flush(),不依赖垃圾回收,且嵌套时按LIFO顺序关闭。

手动关闭文件句柄在异常发生时大概率失效,而 with 语句能强制触发关闭逻辑,这是根本差异。
异常发生时 f.close() 根本不会执行
只要 f.close() 不在 finally 块里,它就不是“无论如何都会运行”的代码。比如写入过程中抛出 UnicodeEncodeError 或磁盘满导致的 OSError,f.close() 后面的语句直接跳过。
- 常见错误现象:
ResourceWarning: unclosed file出现在日志里,或 Windows 下后续打开同一文件报[WinError 32] 另一个程序正在使用此文件 - 即使脚本退出,CPython 会尝试清理,但不保证 flush 缓冲区——数据可能丢失
- 在 PyPy、Jython 等非 CPython 解释器中,未关闭文件的资源回收更不可靠
with 的关闭动作是协议级、同步且确定的
with 不依赖变量作用域或垃圾回收,而是调用文件对象的 __exit__ 方法。这个方法在代码块结束(无论 return、break 还是 raise)时**立即同步执行**,里面明确调用了底层 close() 并自动 flush()。
- 如果用
open(..., buffering=1)(行缓冲),__exit__会先flush()再close() - 如果用
gzip.open()或zipfile.ZipFile(),它们的__exit__还会做校验和写入、索引更新等额外清理 - 嵌套多个
with时,关闭顺序是后进先出(LIFO),这对依赖关系(如os.dup()复制的 fd)很关键
手动加 try/finally 并不比 with 更好,只是更啰嗦
有人觉得“我手写 try/finally 就安全了”,但实际容易漏掉边界情况:
立即学习“Python免费学习笔记(深入)”;
- 忘记判断
f是否成功创建(open()报FileNotFoundError时f未定义,finally里f.close()会抛NameError) - 重复关闭:
f.close()被调两次(比如在except和finally都写了),会触发ValueError: I/O operation on closed file - 多文件场景下,每个都要配独立的
try/finally套子,缩进爆炸,可读性差
真正容易被忽略的是:哪怕你记得写 try/finally,也很难覆盖所有资源依赖场景——比如用 os.fdopen() 包装的原始 fd,或自定义类没正确实现 __exit__ 返回值(该吞异常时不返回 True)。with 是 Python 层面对资源生命周期的硬性约束,不是靠人盯出来的习惯。


















