ファイルを開いた後に close() を呼び忘れると、リソースリークやデータ損失を引き起こす可能性がある。
close() を忘れるとどうなるか
# ❌ アンチパターン
f = open('data.txt', 'w')
f.write('some data')
# close() を忘れている
この場合、以下の問題が発生する可能性がある。
書き込んだデータがディスクに反映されない(バッファに残ったまま)
ファイルディスクリプタが枯渇する
他のプロセスがファイルにアクセスできない(Windows で顕著)
プログラムが異常終了するとデータが消える
例外が発生すると close() されない
close() を書いていても、その前に例外が発生すると呼ばれない。
# ❌ 例外が発生すると close() されない
f = open('data.txt', 'w')
process_data(f) # ここで例外が発生すると…
f.close() # この行は実行されない
try-finally で対処できるが、冗長になる。
# △ 動くが冗長
f = open('data.txt', 'w')
try:
process_data(f)
finally:
f.close()
with 文を使う
with 文を使えば、ブロックを抜けるときに自動的にファイルが閉じられる。例外が発生しても確実に閉じられる。
# ✅ 正しい方法
with open('data.txt', 'w') as f:
f.write('some data')
# ここで自動的に close() される
例外が発生した場合も安全だ。
with open('data.txt', 'w') as f:
process_data(f) # 例外が発生しても
# 確実に close() される
複数ファイルを開く
複数のファイルを同時に開く場合も with 文を使う。
# ✅ 複数ファイルを同時に開く
with open('input.txt', 'r') as fin, open('output.txt', 'w') as fout:
for line in fin:
fout.write(line.upper())
Python 3.10 以降では、括弧で囲んで複数行に分けられる。
with (
open('input.txt', 'r') as fin,
open('output.txt', 'w') as fout,
open('log.txt', 'a') as flog
):
# 処理
pass
pathlib でも with を使う
pathlib の open() メソッドでも同様に with 文を使うべきだ。
from pathlib import Path
path = Path('data.txt')
with path.open('w') as f:
f.write('some data')
ただし、単純な読み書きなら read_text() や write_text() がさらに簡潔だ。
from pathlib import Path
path = Path('data.txt')
# 読み込み
content = path.read_text()
# 書き込み
path.write_text('some data')
これらのメソッドは内部で適切にファイルを閉じるため、with 文を書く必要がない。
ファイルディスクリプタの枯渇
close() し忘れたファイルが蓄積すると、OS のファイルディスクリプタ上限に達してエラーになる。
# ❌ ファイルディスクリプタが枯渇する例
files = []
for i in range(10000):
f = open(f'file_{i}.txt', 'w')
files.append(f) # close() されないファイルが蓄積
# OSError: [Errno 24] Too many open files
with 文を使えばこの問題は発生しない。