Pythonでファイルを with open
してファイルを読む前に return
しちゃうとファイルがクローズしてしまいます。
ValueError: I/O operation on closed file
エラーが発生します。
def load(): with open(...) as f: return csv.reader(f) >>> for row in load(): ... print(row) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: I/O operation on closed file.
こういうときは contextlib.contextmanager
を使ってコンテキストマネージャーにすると、ファイルを全部読み込むまでちゃんとファイルが閉じられません。
import contextlib @contextlib.contextmanager def load(): with open() as f: yield csv.reader(f) >>> with load() as rows: ... for row in rows: ... print(row)
yield from
を使って書くとループの途中で抜けたときにジェネレーターが生き続けるんで、ファイルがクローズされなくなります。
def load(): with open(...) as f: yield from csv.reader(f)
そうするとGCがジェネレーターを消すまでファイルが開きっぱなしになります。
with load()
で書けるようにしとけば、その with
を抜けたときにファイルもクローズされます。
これちょっとイマイチ
— Atsuo Ishimoto (@atsuoishimoto) 2019年4月29日
なんで with open(...) as f: 〜 ってするかって言うと、GCに頼らず、ブロックを抜けたときに確実にcloseするためだけど、これだとファイルを最後まで読まずに抜けたときに GC が動いてジェネレータが開放されるまでファイルがcloseされないのでwithの意味がない
俺だったらこんな感じにする
— Atsuo Ishimoto (@atsuoishimoto) 2019年4月29日
import contextlib
@contextlib.contextmanager
def load():
with open() as f:
yield csv.reader(f)
with load() as rows:
for row in rows:
...
勉強になりました!