ファイル操作などでよく使われる with 文には、実は「コンテキストマネージャー」という仕組みが裏で動いています。
今回はこの仕組みを理解し、自分でコンテキストマネージャーを作る方法についても学びました。
with文の基本的な使い方
まずは、Pythonでよく見る with 文の書き方です。
with open("example.txt", "w") as f:
f.write("Hello, world!")
このコードでは、ファイルが自動的に開かれて閉じられます。
明示的に f.close() を書かなくても、with ブロックを抜けると自動でリソース(ここではファイル)が解放されます。
これができるのは、open() が「コンテキストマネージャー」という仕組みを提供しているからです。
コンテキストマネージャーとは?
「コンテキストマネージャー」は、リソースの開始処理と終了処理をセットで管理するための仕組みです。
Pythonでは、コンテキストマネージャーを作るには __enter__() と __exit__() という特別なメソッドを使います。
自作してみる:基本的なコンテキストマネージャー
次のようにして、自分でクラスを定義することでコンテキストマネージャーを作ることができます。
class MyContext:
def __enter__(self):
print("開始処理:リソースを取得します")
return "リソース"
def __exit__(self, exc_type, exc_value, traceback):
print("終了処理:リソースを解放します")
with MyContext() as value:
print("withブロック内の処理:", value)
開始処理:リソースを取得します
withブロック内の処理: リソース
終了処理:リソースを解放します
-
__enter__():with文に入ったときに実行される -
__exit__():with文から抜けたとき(例外の有無に関係なく)実行される
@contextmanager を使って簡単に書く
クラスで書くと少し面倒なときは、contextlib モジュールの @contextmanager デコレーターを使うと、関数ベースで書けて簡単です。
from contextlib import contextmanager
@contextmanager
def my_context():
print("開始処理")
yield "リソース"
print("終了処理")
with my_context() as value:
print("withブロック内の処理:", value)
開始処理
withブロック内の処理: リソース
終了処理
yield の前が __enter__() の代わり、yield の後が __exit__() の代わりになります。
シンプルなコンテキストマネージャーならこちらの方法が使いやすいです。
おわりに
with 文はただの省略記法ではなく、「リソースの開始と終了を自動管理する」という強力な仕組みを持っています。
今回はその裏側にある __enter__() / __exit__() や @contextmanager を使った実装方法を学びました。
最初は少し複雑に感じましたが、ファイル以外でも応用できると知って理解が深まりました。