1. __enter__, __exit__を実装する
class ContextManagerTest:
# コンテキストマネージャの入り口で実行される処理
# asで受け取る値を返すことができる
def __enter__(self):
print("__enter__")
return self
# コンテキストマネージャの出口で実行される処理
# with文内での例外はexc_type, exc_value, tracebackで情報を受け取ることができる。
def __exit__(self, exc_type, exc_value, traceback):
print("__exit__")
print("exc_type: ", exc_type)
print("exc_value: ", exc_value)
print("traceback: ", traceback)
print("==== close ====")
def error(self):
raise Exception("test exception")
with ContextManagerTest() as t:
t.error()
__enter__
__exit__
exc_type: <class 'Exception'>
exc_value: test exception
traceback: <traceback object at 0x00000279D4256200>
==== close ====
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
...省略
asで受け取った値をwith文外で利用することも可能。ただしその場合は__exit__で例外情報は受け取れない。Close処理などは問題なく実行される。
with ContextManagerTest() as t:
# t.error()
pass
t.error()
__enter__
__exit__
exc_type: None
exc_value: None
traceback: None
==== close ====
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
...省略
例外の伝播を防ぎたい場合は__exit__でTrueを返すようにする。
class ContextManagerTest:
# コンテキストマネージャの入り口で実行される処理
# asで受け取る値を返すことができる
def __enter__(self):
print("__enter__")
return self
# コンテキストマネージャの出口で実行される処理
# with文内での例外はexc_type, exc_value, tracebackで情報を受け取ることができる。
def __exit__(self, exc_type, exc_value, traceback):
print("__exit__")
print("exc_type: ", exc_type)
print("exc_value: ", exc_value)
print("traceback: ", traceback)
print("==== close ====")
return True
def error(self):
raise Exception("test exception")
with ContextManagerTest() as t:
t.error()
__enter__
__exit__
exc_type: <class 'Exception'>
exc_value: test exception
traceback: <traceback object at 0x00000279D82D7240>
==== close ====
2. デコレータを利用する
contextlibモジュールのcontextmanagerデコレータを利用することで、コンテキストマネージャのファクトリ関数を定義することができる。
from contextlib import contextmanager
@contextmanager
def contextmanager_func(*args, **kwds):
print("__enter__")
# 必要なリソースの生成
t = Test()
t.open()
try:
yield t
finally:
# 生成したリソースの開放
t.close()
# 動作確認用クラス
class Test:
def error(self):
raise Exception("test exception")
def open(self):
print("==== open ====")
def close(self):
print("==== close ====")
# 通常のコンテキストマネージャと同様にwith文で利用可能
with contextmanager_func() as t:
print(type(t))
t.error()
__enter__
==== open ====
<class '__main__.Test'>
==== close ====
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
c:\github\TIL\machine_learning\hands_on_machine_learning_with_scikit-learn, keras, and tensorflow\chapter2.ipynb Cell 42 in 2
25 with contextmanager_func() as t:
26 print(type(t))
---> 27 t.error()
c:\github\TIL\machine_learning\hands_on_machine_learning_with_scikit-learn, keras, and tensorflow\chapter2.ipynb Cell 42 in 5
4 def error(self):
----> 5 raise Exception("test exception")
Exception: test exception
例外を処理はtry文の箇所で可能。ただし__enter__, __exit__の時と同様に、with文の例外は処理できない。
@contextmanager
def contextmanager_func(*args, **kwds):
print("__enter__")
t = Test()
t.open()
try:
yield t
except Exception as e:
print(e)
finally:
t.close()
with contextmanager_func() as t:
pass
t.error()
__enter__
==== open ====
==== close ====
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
c:\github\TIL\machine_learning\hands_on_machine_learning_with_scikit-learn, keras, and tensorflow\chapter2.ipynb Cell 42 in 3
27 with contextmanager_func() as t:
28 pass
---> 30 t.error()
c:\github\TIL\machine_learning\hands_on_machine_learning_with_scikit-learn, keras, and tensorflow\chapter2.ipynb Cell 42 in 5
4 def error(self):
----> 5 raise Exception("test exception")
Exception: test exception
コメント