🔖

Pythonのwith文とコンテキストマネージャの仕組みを解説

に公開

はじめに

Pythonでは、ファイル操作やデータベース接続などで with 文がよく使われます。
これは リソースの解放漏れを防ぐ 非常に便利な構文です。

本記事では、with 文の基本的な使い方と、
それを支える「コンテキストマネージャ」の仕組みを解説します。

リソース管理とは?

ファイルやデータベース接続などの「限られた外部資源(リソース)」を使うとき、
開いたら閉じる、使ったら片付けるといった“後処理”が必要になります。

このような処理をプログラムの中で正しく行うことを「リソース管理」と呼びます。

with 文の基本構文

まずは基本の形から見てみましょう。

with open("file.txt", "r") as f:
    data = f.read()

このように書くと、ファイルを開いたあと、処理が終わったタイミングで自動的に f.close() が呼ばれます。
tryfinally を使わずに、安全なリソース管理ができるのが魅力です。

例:データベースでの使用

ファイル以外にも、with はデータベース接続でも使われます。
たとえば Django では、次のように書くことがあります。

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("SELECT COUNT(*) FROM users;")
    count = cursor.fetchone()

このように書くと、カーソルが自動で閉じられるため、
手動で cursor.close() を呼ぶ必要がありません。

with を使わない書き方

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

このように書くことで安全に扱えますが、with を使うとより簡潔に書けます。

with の裏側:コンテキストマネージャとは?

with 文の仕組みを支えているのが コンテキストマネージャ です。

具体的には、以下の2つのメソッドを持つクラスが with に対応しています。

class MyContext:
    def __enter__(self):
        print("開始時の処理")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("終了時の処理")
with MyContext() as ctx:
    print("中の処理")

実行結果:

開始時の処理
中の処理
終了時の処理

このように、__enter__() で準備処理を、__exit__() で後処理を記述できます。

contextlib を使って簡単に書く

標準ライブラリ contextlib を使えば、もっと簡単にコンテキストマネージャが書けます。

from contextlib import contextmanager

@contextmanager
def custom_open(path):
    f = open(path)
    try:
        yield f
    finally:
        f.close()

with custom_open("file.txt") as f:
    print(f.read())

このように、関数ベースでも with の処理が記述できるのは、
Pythonならではの柔軟さと言えるでしょう。

おわりに

with 文は、Pythonにおけるリソース管理の定番手法として、多くの場面で活用されています。

  • ファイル、DB接続、ロック処理などで活躍
  • コンテキストマネージャにより、安全な前処理・後処理が自動で行われる
  • __enter__ / __exit__ を実装すれば、自作も可能

仕組みを知っておくと、より安心して with を使いこなせるようになります。
本記事がその一助となれば幸いです。

Discussion