Pythonのwith文とコンテキストマネージャの仕組みを解説
はじめに
Pythonでは、ファイル操作やデータベース接続などで with
文がよく使われます。
これは リソースの解放漏れを防ぐ 非常に便利な構文です。
本記事では、with
文の基本的な使い方と、
それを支える「コンテキストマネージャ」の仕組みを解説します。
リソース管理とは?
ファイルやデータベース接続などの「限られた外部資源(リソース)」を使うとき、
開いたら閉じる、使ったら片付けるといった“後処理”が必要になります。
このような処理をプログラムの中で正しく行うことを「リソース管理」と呼びます。
with
文の基本構文
まずは基本の形から見てみましょう。
with open("file.txt", "r") as f:
data = f.read()
このように書くと、ファイルを開いたあと、処理が終わったタイミングで自動的に f.close()
が呼ばれます。
try
や finally
を使わずに、安全なリソース管理ができるのが魅力です。
例:データベースでの使用
ファイル以外にも、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