PythonのResourceWarning(unclosed file)の原因と対処法|with文とtracemalloc
先に結論です。ResourceWarning: unclosed file ... は「ファイルや接続を閉じ忘れている」という警告です。with 文を使えば解決します。小さなスクリプトでは実害が出にくいため軽視されがちですが、長く動くプログラムでは確実に問題になります。
どんなメッセージが出るか
ResourceWarning: unclosed file <_io.TextIOWrapper name='data.txt' mode='r' encoding='UTF-8'>
ResourceWarning: Enable tracemalloc to get the object allocation traceback
2行目は「どこで開いたか知りたければ tracemalloc を有効にしてください」という案内です。あとで有効にする方法を説明します。
なぜ閉じ忘れが問題なのか
OSが1つのプロセスに許すファイルの同時オープン数には上限があります。閉じないまま開き続けると、いずれ上限に達します。
OSError: [Errno 24] Too many open files
| プログラムの種類 | 閉じ忘れの影響 |
|---|---|
| 1回動いて終わるスクリプト | ほぼ無害(終了時にOSが回収する) |
| ループで大量のファイルを処理 | 途中で上限に達して落ちる |
| Webサーバー・常駐プロセス | 時間とともに悪化し、いずれ停止 |
| データベース接続 | 接続数の上限に達し、他の処理も巻き添え |
CPythonでは、変数が参照されなくなった時点でファイルが閉じられます。これが「閉じなくても動いてしまう」理由です。ただしこれはCPython固有の動作で、言語の仕様ではありません。PyPyなど他の実装では、いつ閉じられるか保証されません。
直し方|with文を使う
# 悪い例:閉じ忘れる
f = open("data.txt")
data = f.read()
# ここで例外が出たら、close() に到達しない
f.close()
# 良い例:with を使う
with open("data.txt") as f:
data = f.read()
# ブロックを抜けた時点で必ず閉じられる(例外が出ても閉じる)
with の利点は「例外が出ても必ず閉じる」ことです。try / finally を書かなくても同じ効果が得られます。
withが使えるもの
| 対象 | 書き方 |
|---|---|
| ファイル | with open(path) as f: |
| SQLite | with sqlite3.connect(path) as conn:(※注意あり) |
| ソケット | with socket.create_connection(addr) as s: |
| requests | with requests.Session() as s: |
| 複数同時 | with open(a) as f1, open(b) as f2: |
sqlite3の with は接続を閉じません。トランザクションを確定するだけで、接続は開いたままです。紛らわしいので、明示的に conn.close() を呼ぶか、contextlib.closing() で包んでください。
from contextlib import closing
import sqlite3
with closing(sqlite3.connect("db.sqlite")) as conn:
with conn: # ここがトランザクション
conn.execute("INSERT INTO t VALUES (1)")
# ここで接続が閉じられる
どこで開いたか突き止める
警告だけではどの行で開いたファイルか分かりません。2つの方法で特定できます。
1. tracemalloc を有効にする
python -X tracemalloc=5 your_script.py
開いた場所のトレースバックが警告と一緒に表示されます。数字は遡る段数です。
2. 警告をエラーにする
python -W error::ResourceWarning your_script.py
警告が例外になり、閉じ忘れが検出された時点で処理が止まります。ただし止まるのは「閉じ忘れが判明したとき」で、開いた行ではありません。場所の特定には tracemalloc のほうが有効です。
なぜ普段は表示されないのか
ResourceWarningは既定で表示されません。利用者に見せる必要のない情報だと判断されているためです。
# 表示する
python -W always::ResourceWarning your_script.py
# コードの中から有効にする
import warnings
warnings.simplefilter("always", ResourceWarning)
開発中やテストでは有効にしておくことを勧めます。本番で Too many open files が出てから探すより、はるかに楽です。
よくある質問
無視しても動いていますが、直すべきですか?
直すべきです。1回で終わるスクリプトなら実害はありませんが、そのコードがループの中や常駐プロセスに移ったときに問題になります。
with文を使っているのに警告が出ます
別の場所で開いています。ライブラリの内部や、open() を直接呼んでいる箇所を探してください。-X tracemalloc=5 で場所が分かります。
Too many open files が出ました
閉じ忘れが上限に達しています。上限を上げる前に、まず閉じ忘れを直してください。上限を上げても、漏れ続ける限りいずれ同じことが起きます。
requestsでも出ますか?
出ます。requests.Session() を使い捨てにしていると警告されます。with requests.Session() as s: で包んでください。
関連記事
実行時の警告はRuntimeWarning、ファイルが見つからない場合はFileNotFoundErrorをご覧ください。
Pythonのエラー全般はPythonでよく出るエラー一覧、例外処理の書き方はPythonの例外処理(try except)、警告の扱い方はPythonのWarningにまとめています。
テックジムは月額22,000円の通い放題でプログラミング教室を運営しています。東京本校(永田町)では毎週土曜にゼロから始めるPython入門講座、そしてゼロから始めるClaude Code講座を無料で開いています。どちらも説明会ではなく実際に手を動かす講座です。
まとめ
ResourceWarning: unclosed file は閉じ忘れの警告です。with 文を使えば、例外が出ても必ず閉じられます。
1回で終わるスクリプトなら実害はありませんが、ループや常駐プロセスでは Too many open files で落ちます。場所を特定したいときは python -X tracemalloc=5 で実行してください。sqlite3の with は接続を閉じない点にも注意です。




