😺

【Python入門】with構文について調べたことまとめ

に公開

はじめに

with構文を使わなかった場合
try:
    # "example.txt"を書き込みモード("w")で開き、ファイルがなければ新規作成する
    # 既存のファイルであれば内容をすべて消去して上書きする
    # 文字コードはUTF-8を指定
    f = open("example.txt", "w", encoding="utf-8")
    # ファイルにcontentを書き込み
    f.write(content)
except Exception as e:
    print(f"エラーが発生しました: {e}")
finally:
    # ファイル書き込み終了した場合
    if f is not None:
        # 例外の有無にかかわらず、ファイルオブジェクトfが存在する場合にファイルを閉じる
        f.close()
with構文を使った場合
with open("example.txt", "w", encoding="utf-8") as f:
    f.write(content)

with構文を使うことで try-except 文を記述しなくてもファイルを開いてから閉じるまでを行なうことができますが、これはどういう仕組みでこのようになっているのか、簡単にまとめていきます。

with構文とは

ファイルの開閉やデータベース接続など、特定のコンテキストにおけるリソース管理を簡潔かつ安全に行うためのものです。

この構文を使うと、処理が正常に完了したか、エラーが発生したかにかかわらず、リソースの解放(クローズ)が自動的に保証されます。

例えばファイル操作で言うと、open() から close() までがセットですが、with構文を使用する場合、close()を明示する必要がなくなります。
これにより、withブロックを抜ける際に、ファイルの閉じ忘れを防ぐことができます。

with構文の仕組み

なぜ close() が不要なのでしょうか?
with構文が try-except-finally ブロックを簡潔にするのは、コンテキストマネージャという仕組みがあるからです。これは、リソースの取得と解放を自動的に行なうプロトコル(規約)にすぎません。

コンテキストマネージャとは

with構文が使用できるオブジェクトは、コンテキストマネージャプロトコルを実装している必要があります。これは、特別な2つのメソッドを持つオブジェクトに適用される規約です。

  • __enter__() メソッド
    withブロックが開始される際に呼び出されます。このメソッドは、ファイルを開くなど、リソースを取得する役割を担います。asキーワードに続く変数に代入される値は、このメソッドの戻り値です。

  • __exit__() メソッド
    withブロックが終了する際に必ず呼び出されます。ブロック内でエラーが発生したかどうかに関わらず、このメソッドが実行されるため、ファイルのクローズなど、リソースを確実に解放できます。

ファイルオブジェクトの2つの役割

open("example.txt", "w", encoding="utf-8")

この関数の結果としてファイルオブジェクトが返されますが、実はこのファイルオブジェクトには2つの役割があります。

1. ファイルオブジェクトとしての役割

これは、ファイルに対する読み書きやその他の操作を可能にする基本的な役割です。
read(), write(), close() などのメソッドを通じて、プログラムとストレージ上のファイルを結びつけます。

2. コンテキストマネージャとしての役割

この役割はwith構文と組み合わせて発揮されます。
withブロックに入るときに __enter__() メソッドが、withブロックを抜けるときに __exit__() メソッドが自動的に呼び出されます
この仕組みによって、リソースの取得(ファイルのオープン)と解放(ファイルのクローズ)が、自動で安全に行われます。

したがって、

# with open(...) as f: この行の処理
# 1. open() 関数がファイルオブジェクトを作成
# 2. そのファイルオブジェクトの __enter__() メソッドが呼び出される
# 3. __enter__() メソッドの戻り値が変数fに代入される

with open("example.txt", "w", encoding="utf-8") as f:
    # このブロック内の処理
    f.write(content)

# withブロックの終了時
# 1. fに代入されていたオブジェクトの __exit__() メソッドが呼び出される
# 2. __exit__() 内で f.close() が実行される

このようなことが内部的に行われており、これによって、自動的にリソースの取得と解放をします。

open() 関数が返すファイルオブジェクトは、このコンテキストマネージャプロトコルを実装しています。そのため、with open(...) as f: という形で利用できます。

この構文を使用することで、Pythonは内部的に以下の処理を自動で行ないます。

まとめ

with構文が単なるコードの省略記法ではなく、リソース管理を自動化する安全な仕組みであることが理解できたかと思います。

重要なポイントはコンテキストマネージャと自動実行の仕組みがあることです。

with構文を使いこなすことで、より安全で、より読みやすいコードを書くことができます。
ファイル操作に限らず、データベース接続など、さまざまな場面で活用できるようなので、ぜひ、開発に役立ててください。

最後までお読みいただき、ありがとうございました。

参考URL

https://zenn.dev/k41531/articles/9c566a778b79ca

https://docs.python.org/ja/3/reference/compound_stmts.html#the-with-statement

https://docs.python.org/ja/3/library/stdtypes.html#context-manager-types

https://python-hack.net/basic-of-with-statement/

http://zenn.dev/aiq_dev/articles/0e198d8b6f2aa7

Discussion