Написание собственного менеджера контекста

Менеджер контекста является любой объект , который реализует два магических методов __enter__() и __exit__() (хотя он может реализовать другие методы, а):

 class AContextManager():

    def __enter__(self):
        print("Entered")
        # optionally return an object
        return "A-instance"

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exited" + (" (with an exception)" if exc_type else ""))
        # return True if you want to suppress the exception

 

Если контекст выходит с исключением, информация о том , что исключение будет передан как тройной exc_type , exc_value , traceback (это те же переменные , как возвращаемое sys.exc_info() функции). Если контекст выходит нормально, все три из этих аргументов не будет None .

Если исключение происходит , и передается в __exit__ метод, метод может возвращать True , чтобы подавить исключение, или исключение будет вновь поднят в конце __exit__ функции.

 with AContextManager() as a:
    print("a is %r" % a)
# Entered
# a is 'A-instance'
# Exited

with AContextManager() as a:
    print("a is %d" % a)
# Entered
# Exited (with an exception)
# Traceback (most recent call last):
#   File "<stdin>", line 2, in <module>
# TypeError: %d format: a number is required, not str

 

Следует отметить , что во втором примере , даже если исключение происходит в середине тела с-заявлением __exit__ обработчик еще запускается на выполнение, до того , как исключение распространяется на внешнюю область.

Если вам необходим только __exit__ метод, вы можете вернуть экземпляр менеджера контекста:

 class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self):
        print('something')