blank page

プログラミングなどについて書きます

pythonのwith文を勉強する

ここでのpythonはすべてpython3です.


こんにちは. 冬休みに入りますが遊んでくれる人がいないのでpythonのwith文を調べます。

with構文とはなにか

with 文は、ブロックの実行を、コンテキストマネージャによって定義されたメソッドでラップするために使われます。

8. 複合文 (compound statement) — Python 3.6.3 ドキュメント

Example

with open("hoge.txt", "w") as f:
    f.write("Hello World!")

# 上記のコード等価です
# f = open("hoge.txt", "w")
# f.write("Hello World!")
# f.close()

with文の動き

  1. コンテキスト式を評価することで,コンテキストマネージャを取得
  2. コンテキストマネージャの __exit__() メソッドが、後で使うためにロードされる
  3. コンテキストマネージャの __enter__() メソッドが呼ばれる
  4. with文にターゲットが含まれていたら, それに __enter__() からの戻り値が代入される
  5. スイートが実行
  6. コンテキストマネージャの __exit__() が呼ばれる(以下略)

8. 複合文 (compound statement) — Python 3.6.3 ドキュメント

らしいです.
with文が使えるのは __enter____exit__ が定義されているclassらしいです.
:thinking_face: って感じなので実際に書いて動かしてみます.

試してみる

class Test_with:
    def __init__(self):
        print("__init__")

    def __enter__(self):
        print("__enter__")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("__exit__")
        print("exc_type: ", exc_type)
        print("exc_value: ", exc_value)
        print("traceback: ", traceback)

    def __del__(self):
        print("__del__")

    def say(self):
        print("Hello!")


def main():
    print("*** start main function ***")
    with Test_with() as test:
        print("test: ", test)
        print("*** start `with` ***")
        test.say()
        print("*** end `with` ***")
    print("*** end main function ***")


if __name__ == "__main__":
    main()

出力結果は以下になります.

*** start main function ***
__init__
__enter__
test:  <__main__.Test_with object at 0x7f257ec15978>
*** start `with` ***
Hello!
*** end `with` ***
__exit__
exc_type:  None
exc_value:  None
traceback:  None
*** end main function ***
__del__

with文の動きというセクションで引用した説明と一緒に動きを追ってみます.

おいかけます

コンテキスト式を評価することで,コンテキストマネージャを取得

コンテキストマネージャは __enter____exit__ メソッドを持つオブジェクトです.
コンテキストマネージャについては

Pythonのコンテキストマネージャは何が嬉しいのか? - Qiita

が詳しく書かれています.

Test_withクラスをインスタンス化してコンテキストマネージャとして取得してるっぽいです.(多分)
なので, 出力結果を見ると __init__ がまず呼ばれていることがわかります.


コンテキストマネージャの __exit__ メソッドが, 後で使われるためにロードされる

ロードされてるらしいです.


コンテキストマネージャの __enter__ メソッドが呼ばれる.

出力結果で __init__ の次に __enter__ が表示されているので __enter__ メソッドが呼ばれていることがわかります.


with文にターゲットが含まれていたら, それに __enter__メソッドからの戻り値が代入される

__enter__self を返したので, with文のところの as で指定した test__enter__ の返り値が代入されています.


スイートが実行

with文のブロック内の処理が実行されています.


コンテキストマネージャの __exit__メソッドが呼ばれる

出力結果を見るとwith文のブロック内の処理が終わってから __exit__メソッド内で定義した処理が実行されているので, __exit__ メソッドが呼ばれていることがわかりますね.

まとめ

with文良さ.
また今度, 説明の部分の(以下略)を追っていきます.

(以下略部分を適当に書きました)
nve3pd.hatenablog.com

参考文献

8. 複合文 (compound statement) — Python 3.6.3 ドキュメント
3. データモデル — Python 3.6.3 ドキュメント
Pythonのコンテキストマネージャは何が嬉しいのか? - Qiita