Python contextlibとは?with文を自作する方法を解説
Pythonのcontextlibは、with文を自分で作るための道具をまとめたモジュールです。
with open(...)の「必ず後始末される」仕組みを、自分の処理にも持ち込めます。
with文が何をしているか
contextlibを理解するには、まずwithの仕組みを押さえる必要があります。
class Timer:
def __enter__(self):
print(" __enter__ が呼ばれた")
return "戻り値"
def __exit__(self, exc_type, exc, tb):
print(f" __exit__ が呼ばれた exc_type={exc_type}")
return False
with Timer() as t:
print(" 中身:", t)
実行結果:
__enter__ が呼ばれた
中身: 戻り値
__exit__ が呼ばれた exc_type=None
withは3つのことをします。
__enter__()を呼ぶ- その戻り値を
asの変数に入れる - ブロックを抜けるとき
__exit__()を呼ぶ
例外が起きても__exit__は必ず呼ばれる
try:
with Timer():
raise ValueError("失敗")
except ValueError as e:
print(" 外で捕捉:", e)
実行結果:
__enter__ が呼ばれた
__exit__ が呼ばれた exc_type=<class 'ValueError'>
外で捕捉: 失敗
これがwithの価値です。ファイルのクローズ、ロックの解放、接続の切断——「必ずやらなければならない後始末」を書き忘れずに済みます。
__exit__には発生した例外の情報が渡ってきます。何も起きなければNoneです。
__exit__がTrueを返すと例外が消える
class Swallow:
def __enter__(self): return self
def __exit__(self, *a): return True
with Swallow():
raise ValueError("消える")
print(" 例外が握りつぶされた")
実行結果:
例外が握りつぶされた
Trueを返すと「この例外は処理した」という意味になり、外へ伝わりません。False(またはNone)なら、そのまま外へ投げられます。
意図せずTrueを返すとエラーが消えます。握りつぶすつもりがないなら、__exit__では何も返さないでください。
contextlibで書くと短くなる
クラスを書かずに、関数だけで同じことができます。
from contextlib import contextmanager
@contextmanager
def tag(name):
print(f"<{name}>")
yield
print(f"</{name}>")
with tag("p"):
print(" 本文")
実行結果:
<p>
本文
</p>
yieldの前が__enter__、後ろが__exit__に相当します。クラス定義が不要になり、ぐっと読みやすくなります。
詳しくは「Python @contextmanagerとは?with文を関数で作る方法」で解説しています。
contextlibの主な機能
| 機能 | 用途 | 解説記事 |
|---|---|---|
@contextmanager |
with文を関数で作る | contextmanager |
suppress() |
特定の例外を無視する | suppress |
closing() |
close()だけの相手をwithで扱う |
closing |
redirect_stdout() |
出力先を差し替える | redirect_stdout |
ExitStack() |
数が決まらない後始末をまとめる | ExitStack |
nullcontext() |
「何もしない」with | 下記参照 |
nullcontext|条件によってwithを使い分ける
from contextlib import nullcontext
def process(path=None):
cm = open(path, encoding="utf-8") if path else nullcontext()
with cm as f:
return f.read() if f else "(標準入力の代わり)"
print(process("a.txt"))
print(process())
実行結果:
A
(標準入力の代わり)
「ファイルが指定されたら開く、なければ何もしない」——同じwithで両方を書けます。ifで処理を二重に書かずに済みます。
nullcontext()はNoneを返すだけの、何もしないコンテキストマネージャです。
いつ自作するか
| 場面 | 例 |
|---|---|
| 必ず後始末が必要 | 接続の切断・ロックの解放・一時ファイルの削除 |
| 前後で対になる処理 | 計測の開始と終了・インデントの増減 |
| 状態を一時的に変える | 設定の差し替え・作業ディレクトリの移動 |
| 使い終わりを強制したい | 使う側にclose()を忘れさせない |
逆に、後始末が不要ならwithにする意味はありません。単なる関数で十分です。
contextlibのまとめ
withは__enter__と__exit__を呼ぶ仕組み- 例外が起きても
__exit__は必ず実行される __exit__がTrueを返すと例外が消える@contextmanagerならクラスを書かずに済む- 例外を無視するなら
suppress()、close()だけの相手にはclosing() - 数が決まらないなら
ExitStack()






