コンテキストマネージャ
Pythonではwith文で前処理、後処理を行えるようにする場合、そのオブジェクトはコンテキストマネージャである必要があります。
次のように特殊メソッド「__enter__」「__exit__」を実装すれば、そればすでにコンテキストマネージャです。 「__enter__」の処理、「with」ブロックの処理、「__exit__」の処理が順に実行されます。
# -*- coding: utf-8 -*-
class ContextManagerTest:
def __enter__(self):
print '__enter__'
def __exit__(self, exc_type, exc_value, traceback):
print '__exit__'
with ContextManagerTest():
print 'with'
--実行結果--
__enter__ with __exit__
「__exit__」の引数で渡される情報は例外発生時に活用できます。 ここでは「__exit__」の戻り値としてTrueを返していますが、この場合は例外が発生しても処理がストップすることはありません。そのまま処理を継続します。 Falseを返した場合は無視できないエラーとして、通常の例外のように処理がそこでストップします。
# -*- coding: utf-8 -*-
class ContextManagerTest:
def __enter__(self):
print '__enter__'
def __exit__(self, exc_type, exc_value, traceback):
print '__exit__'
print exc_type
print exc_value
print traceback
return True
with ContextManagerTest():
val = int('abc')
--実行結果--
__enter__ __exit__ <type 'exceptions.ValueError'> invalid literal for int() with base 10: 'abc' <traceback object at 0x0000000002A7E6C8>
asで渡されるオブジェクトは「__enter__」の戻り値で指定することができます。
# -*- coding: utf-8 -*-
class ContextManagerTest:
def __enter__(self):
print '__enter__'
return 'as obj'
def __exit__(self, exc_type, exc_value, traceback):
print '__exit__'
with ContextManagerTest() as as_obj:
print as_obj
--実行結果--
__enter__ as obj __exit__
こちらはデコレータを使用するやり方です。 より簡単にコンテキストマネージャを作成することができ、クラスだけではなく関数もコンテキストマネージャとすることができます。
# -*- coding: utf-8 -*-
from contextlib import contextmanager
@contextmanager
def context_manager_test():
print 'enter'
yield
print 'exit'
with context_manager_test():
print 'with'
--実行結果--
enter with exit
asで渡されるオブジェクトは「yield」で指定することができます。
# -*- coding: utf-8 -*-
from contextlib import contextmanager
@contextmanager
def context_manager_test():
print 'enter'
yield 'as_obj'
print 'exit'
with context_manager_test() as as_obj:
print as_obj
--実行結果--
__enter__ as obj __exit__
関数で定義?デコレータで定義?
▶応用編:プロパティ
