コンテキストマネージャ

Pythonではwith文で前処理、後処理を行えるようにする場合、そのオブジェクトはコンテキストマネージャである必要があります。

特殊メソッドを実装する

次のように特殊メソッド__enter____exit__を実装すれば、そればすでにコンテキストマネージャです。__enter__の処理、withブロックの処理、__exit__の処理が順に実行されます。

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を返した場合は無視できないエラーとして、通常の例外のように処理がそこでストップします。

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__」の戻り値で指定することができます。

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__

デコレータを使用する

こちらはデコレータを使用するやり方です。より簡単にコンテキストマネージャを作成することができ、クラスだけではなく関数もコンテキストマネージャとすることができます。

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」で指定することができます。

from contextlib import contextmanager


@contextmanager
def context_manager_test():
    print('enter')
    yield 'as_obj'
    print('exit')


with context_manager_test():
    print(as_obj)
enter
as obj
exit