Pythonのwithを理解する
投稿日: 更新日:
端的にwith文とは
ある処理の前と後に必要な処理を扱う物です。
コンテキストマネージャー
コンテキストマネージャーとはwith
文の実行に必要な物を定義したオブジェクトです。
コードは以下の通りです
class ContextManager:
def __init__(self):
print("初期化")
def __enter__(self):
print('前処理')
def __exit__(self, exc_type, exc_value, traceback):
"""
exc_type: 例外のクラス
exc_value: メッセージ
traceback: tracebackオブジェクト
"""
print("後処理")
これをwith
文で実行すると以下のようになります。
with ContextManager():
print("何らかの処理")
実行結果
初期化
前処理
何らかの処理
後処理
処理の流れを画像でまとめると以下の通りです
※補足:with
文は__enter__
が正常に終了すれば__exit__
は必ず実行されます。
引数、戻り値
__init__
で引数を受け取る__enter__
の戻り値はas
で受け取る
例としてファイルのオープンを考えます。
コンテキストマネージャーを以下のように定義します。
class ContextManager:
def __init__(self, path):
print("初期化")
self.path = path
self.file = None
def __enter__(self):
print('前処理')
self.file = open(self.path)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
print("後処理")
print(f'exit: {exc_type}, {exc_value}, {traceback}')
self.file.close()
これを用いてコードを書くと以下のようになります。
with ContextManager("text.txt") as f:
print(f.readline())
例外
with
文中で例外が起こった場合すべて__exit__
に与えられます。
with
文が例外で終了された場合、 __exit__
の戻り値がTrue
であれば例外は抑制されwith
の続きが処理されます。False
であれば例外が再送出されます。
例えばこのようなクラスを定義します
class ContextManager:
def __init__(self, retu):
self.retu = retu
def __enter__(self):
pass
def __exit__(self, exc_type, exc_value, traceback):
print(f'exit: {exc_type}, {exc_value}, {traceback}')
return self.retu
戻り値をTrue
にして実行すると
with ContextManager(True):
raise ValueError("Error!")
print("next...")
出力はこのようになります
exit: <class 'ValueError'>, Error!, <traceback object at 0x000002084EA37340>
next...
このように例外が発生しても次の処理が行われていることが分かります。