with構文


ファイルを読み込む時などwithという構文を良く使います。これをするとcloseしなくていいらしいですが、なぜ大丈夫なのでしょうか。

本当にcloseされているの?

そもそもwithでくくった部分、本当にcloseされているのでしょうか?試しに下記のコードを実行してみます。

with open("data.txt", "r") as f:
    data = f.read()
data2 = f.read()

実行結果

$ ./with.py 
Traceback (most recent call last):
  File "./with.py", line 6, in <module>
    data2 = f.read()
ValueError: I/O operation on closed file.

結果は、たしかにdata2を代入する所で既にcloseされているとエラーになり終わりました。

終了時の動作がクラスで定義されている。

実はwithでくくった部分が終了する時にどういう動きをするのかがクラスで定義されています。 openはちょっと追いかけるのが大変だったのでMySQLのPyMySQLの例で見てみましょう。

cursor.pyには下記のような定義があります。

   def __exit__(self, *exc_info):
       del exc_info
       self.close()

これはwithでくくった部分が終了した時の処理です。ここではclose()が実行されるようになっています。

動きはクラス定義によって変わる。

withはマクロに近いようなものなので、使うクラスによって動きが変わってきます。open関数の場合は終了時にcloseが実行されますが、他の関数では違うかもしれません。withを使う時はその関数の仕様を十分確認する必要がありそうです。