Pythonのwithステートメントのまとめ
Pythonを使う上で、withステートメントは、やはり見逃せない機能の1つであると思います。
Python2.5〜3.xまで網羅しているようにしたつもりです。
基本
まず、一番身近なファイル操作の例を載せておきます。
with open("...") as f: print(f.read())
これは、以下と同等です。
f = open("...") print(f.read()) f.close()
withステートメントを使うと、withを抜けた時に、自動的にf.close
されます。
as
は必須ではありません。
f = open("...") with f: print(f.read())
これも先ほどのコードと同等です。
withに対応したクラスを作る
使うだけでは理解も深まらないので、作る方も見てみましょう。
withに渡すのは__enter__
と__exit__
の2つのメソッドを持ったクラスのインスタンスです。
class Test: def __init__(self, hoge): print("init") self.hoge = hoge def printHoge(self): print(self.hoge) def __enter__(self): print("enter") return self def __exit__(self, type, value, traceback): print("exit") with Test("hoge") as t: t.printHoge()
出力
init enter hoge exit
withステートメントに入る時にTest#__enter__
が、出る時にTest#__exit__
が呼ばれます。as
で指定する変数には、Test#__enter__
の戻り値が入るので、上記のサンプルでreturn self
しているところがミソです。
__exit__
の引数は、with内部で例外が発生した時以外はNoneのようです*1。
__exit__を上手く使っている良い実例を見つけました → Pythonのwith構文で例外を補足する実例 - $ cat /var/log/shin
Tips
複数のwith
以下のように、複数のファイルを同時に開いて何かしたいケースが有るかもしれません。
with open("...") as f1: with open("...") as f2: # ...
この時、Python 2.7以降ではカンマ区切りで複数指定することが可能です。
with open("...") as f1, open("...") as f2: # ...
ちなみに、Python 2.7未満ではcontextlib.nestedを使う方法があるようです。
# 2.7以降では非推奨 import contextlib with contextlib.nested(open("..."), open("...")) as (f1, f2): # ...