コピペ&結論メモ
PYTHON
class testContextManager:
#②enterが実行されて、値を返却(例だとself)
def __enter__(self):
print("enter")
return self
#⑥ブロック実行後にexitが実行される
def __exit__(self, ex_type, ex_value, trace):
print("exit")
#⑤enterの返却値(self)を利用してメソッドを実行
def method(self):
print("method")
#①with文で指定したコンテキストマネージャークラスのenterが実行
#③enterの返却値がtargetにセットされる
with testContextManager() as target:
#④ブロック内が実行される
print("block")
target.method()
実行結果(>の先が出力結果):
>enter
>block
>method
>exit
自分的まとめ:
前後処理を共通化したい時に使う。
コンテキストマネージャが生成されるときにenterが呼ばれ、Withブロックから抜ける時にexitが呼ばれる。例外が発生しても必ずexitが実行されるので、finalとして使うことで、後処理書き忘れ防止になる。
__enter__と__exit__を書くのが面倒・不要な場合は、デコレータを使ったコンテキストマネージャーを用意することで対応。
@contextlib.contextmanagerについて
ジェネレーターをこの@contextlib.contextmanagerでデコレートするとコンテキストマネージャーになる。
ジェネレーターとは、returnの代わりにyieldで値を返す関数のこと。
この場合、__enter__と__exit__の実装が不要になる。
PYTHON
from contextlib import contextmanager
#②コンテキストマネージャーになったfuncが実行される。
@contextmanager
def func():
try:
print("func")
③yieldで指定した値を返却する。
yield "yield"
finally:
⑤withのブロックを抜けた後、finallyが実行される。
print("final")
#①with文で指定したコンテキストマネージャーを実行
with func() as target:
#④yieldの値がtargetセットされ、ブロック内が実行される
print("block")
print(target)
実行結果(>の先が出力結果):
>func
>block
>yield
>final
その他の気づいたこと、学んだことメモ
- exitで、Trueを返却すればエラーを握りつぶせる
- withをつかわず、単純にインスタンスを生成して実行した場合、コンテキストマネージャが動かないので、enterとexitは勝手に動くことはない。
- ファイル操作はそもそもコンテキストマネージャー型だから、自分でコンテキストマネージャーを作る必要が無く、勝手にクローズされる。
- デコレートしたコンテキストマネージャからすればどんなブロックが実行されるか分からないので、yieldをtry/finalで囲む必要がある。囲まないと、後処理がエラーだと動かなくなる事態になる。