自分なりにPythonのwith構文を解釈してみた

ことのはじめ

TwitterPythonのwith構文分からん、って言ってる人がいて、てけとーに返事してしまったのだが、ふと調べてみたら違ったのでちゃんと理解しておこうと思った。

実際のwith構文

withはclassの生成と削除をコントロールすることで、RAIIを実現する手法。ローンパターンとか呼ばれている。Cとかだと良くあるメモリ開放忘れや、ファイルのclose忘れを回避する。

Pythonのwithは特別なclassが必要、という訳ではなく、通常のclassに特定の数の引数を持つ__enter__メソッドと__exit__メソッドがあればいい。

例えばこんな感じ

class withTest(object):
    def __init__(self, lst):
        self.lst = lst

    def put(self, it):
        self.lst.append(it)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for l in self.lst:
            print l
        return True

if __name__ == "__main__":
    with withTest(["a", "b"]) as w:
        w.put("c")

これでa, b, cが出力される。

__enter__

コンストラクタの後に呼び出される。引数を持たず、生成時の引数はコンストラクタに直接渡される。このメソッドの返り値がas以下に代入される。(この為上記ではselfを指定している)

__exit__

withステートメントを抜けた際に呼び出される。3つの引数を持つ。Trueを返すと例外はそのまま伝搬するし、Falseだと例外を伝搬しない。