Python の with 文とは

with 文は、リソースの確保と解放を自動的に行うための構文です。ファイルやネットワーク接続など、使い終わったら必ず後始末が必要なリソースを安全に扱えます。

with 文の基本

最もよく使われるのは、ファイル操作です。

with open("data.txt", "r") as f:
    content = f.read()
    print(content)
# ブロックを抜けると自動的にファイルが閉じられる

with ブロックを抜けると、正常終了でも例外発生でも、必ずファイルが閉じられます。

with 文を使わない場合

with を使わないと、自分で close() を呼ぶ必要があります。

f = open("data.txt", "r")
try:
    content = f.read()
    print(content)
finally:
    f.close()

try-finally を毎回書くのは面倒ですし、書き忘れるとリソースリークの原因になります。with 文を使えば、こうした問題を防げます。

なぜ with 文が必要か

with 文なし

close() の呼び忘れリスクがある。例外発生時の処理が複雑になる。コードが冗長になる。

with 文あり

自動的にリソースが解放される。例外が発生しても安全。コードが簡潔になる。

with 文の動作

with 文は内部で以下の処理を行っています。

enter() を呼び出す

ブロック内のコードを実行

exit() を呼び出す(例外の有無に関わらず)

__enter__()__exit__() を持つオブジェクトを「コンテキストマネージャ」と呼びます。

as 句の省略

リソースを変数に束縛する必要がなければ、as は省略できます。

from threading import Lock

lock = Lock()

with lock:  # as を省略
    # ロックを保持した状態で処理
    print("クリティカルセクション")

標準ライブラリのコンテキストマネージャ

Python の標準ライブラリには、多くのコンテキストマネージャが用意されています。

# ファイル操作
with open("file.txt") as f:
    pass

# スレッドロック
from threading import Lock
with Lock():
    pass

# 一時ディレクトリ
from tempfile import TemporaryDirectory
with TemporaryDirectory() as tmpdir:
    print(tmpdir)

# データベース接続(sqlite3)
import sqlite3
with sqlite3.connect("test.db") as conn:
    pass

with 文を積極的に使うことで、リソース管理のバグを減らし、コードの可読性を高められます。