ResourceWarning: unclosed file 表示文件对象被垃圾回收器强制关闭,而非主动调用close(),通常因未用with或手动close导致;应将裸open()替换为with open(),并注意多文件时反向关闭顺序,可用tracemalloc定位泄漏点。

ResourceWarning: unclosed file 是什么信号
这不是错误,但比错误更危险——它说明 Python 已经在帮你善后:某个 _io.BufferedReader 或 _io.TextIOWrapper 对象被垃圾回收器(GC)强制关闭了,而你本该自己关。这通常发生在 open() 后没配 close(),也没用 with 的地方。Windows 上可能紧接着出现 PermissionError: [WinError 32],Linux/macOS 则容易耗尽文件描述符上限。
直接修复:把 open() 换成 with open()
几乎所有漏关文件的场景,都能靠一行改写解决。关键不是“加个 with”,而是替换掉裸 open() 调用:
- 错:
parser = pickle.load(open("data.pkl", "rb"))→ 文件对象无变量引用,无法 close - 对:
with open("data.pkl", "rb") as f: parser = pickle.load(f) - 错:
files = {"file": open("upload.txt", "rb")}→ request 发完请求后文件仍开着 - 对:
with open("upload.txt", "rb") as f: files = {"file": f} requests.post(url, files=files)
注意:with 块退出时,__exit__ 会同步调用 close(),不等 GC,也不依赖变量是否被 del 或重赋值。
嵌套多个文件时的顺序陷阱
Python 3.1+ 支持逗号分隔写法,但关闭顺序是反向的——后打开的先关。这点在资源有依赖时很关键:
立即学习“Python免费学习笔记(深入)”;
-
with open("a.txt") as f1, open("b.txt") as f2:→f2.close()先执行,f1.close()后执行 - 如果
f2是基于f1.fileno()复制的句柄(如os.dup()),必须保证原句柄f1后关,否则f2可能失效 - Python 2.7 不支持逗号写法,得嵌套:
with open("a") as f1: with open("b") as f2: - 绝对别写
with open("a") as f1, f2:—— 这是语法错误,f2不是上下文表达式
tracemalloc 能帮你定位哪行漏关
当警告里带 Enable tracemalloc to get the object allocation traceback,说明 Python 已经给你留了线索:
在脚本开头加两行:
import tracemalloc tracemalloc.start()
运行后警告会变成类似:
ResourceWarning: unclosed file <_io.TextIOWrapper name='config.ini' mode='r' encoding='utf-8'> File "app.py", line 42, in load_config f = open("config.ini")
注意:这个回溯指向的是 open() 调用位置,不是警告触发位置——修那里就对了。
真正难处理的,往往是第三方库内部用了裸 open()(比如 pynq 的 embedded_device.py)。这种时候你没法改源码,只能临时过滤警告,或提 issue。但自己的代码,永远优先用 with。


















