不手动调用 close() 会导致文件句柄持续占用,引发“Too many open files”错误,且在 PyPy、异常中断等场景下无法可靠释放;应优先使用 with 语句确保自动关闭。

不手动调用 close() 会导致什么
Python 的文件对象底层绑定操作系统句柄(如 Unix 的 fd、Windows 的 HANDLE),一旦打开未关闭,该句柄会持续占用直到进程退出。常见现象包括:OSError: [Errno 24] Too many open files,尤其在循环打开大量文件或长期运行的 Web 服务中极易触发。即使脚本结束,CPython 通常能靠引用计数自动回收,但这是不可靠的——PyPy、Jython 或异常中断(如 KeyboardInterrupt)下可能跳过析构逻辑。
优先用 with 语句而非 try/finally
with 是最简洁可靠的方案,它保证无论是否发生异常都会执行 __exit__(即隐式调用 close())。相比手写 try/finally,它更少出错、更易读。
with open('data.txt', 'r') as f:
content = f.read()
# 即使这里 raise Exception,f 仍会被关闭
# 此处 f 已关闭,再访问 f.read() 会报 ValueError
- 不要在
with块外继续使用文件对象变量,它已处于关闭状态 - 多个文件可链式书写:
with open('a.txt') as a, open('b.txt') as b: - 若需延迟关闭(极少数场景),必须明确写出
try/finally并在finally中调用f.close()
显式调用 close() 的风险点
手动 close() 看似直接,但容易遗漏或重复调用:
- 忘记写
close()—— 尤其在分支逻辑多、return 分散的函数里 - 重复调用
close()不报错,但后续再读写会抛ValueError: I/O operation on closed file - 在
except块中只处理了部分异常,漏掉其他中断路径(如信号、sys.exit()) -
close()本身可能抛异常(如磁盘满导致 flush 失败),需额外捕获,而with默认忽略这类错误
检查文件是否已关闭:用 f.closed 而非异常试探
调试时想确认状态,直接查 f.closed 属性最稳妥。别用 try: f.read() except ValueError 判断——这既低效又掩盖真实问题。
with open('test.log', 'w') as f:
print(f.closed) # False
print(f.closed) # True
-
f.closed是只读布尔属性,安全可靠 - 对已关闭文件再次调用
close()是合法的(无副作用),但没必要 - 注意:某些封装类(如
gzip.GzipFile)也支持.closed,行为一致
实际项目里,99% 的文件操作都该走 with。只有当你需要跨作用域持有文件句柄(比如传给另一个函数并由它决定何时关),才考虑手动管理——这时务必配 try/finally,且在 finally 里加 if not f.closed: f.close() 防重入。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











