Как работает контекстный менеджер в ПИТОНЕ

from contextlib import contextmanager

@contextmanager
def nullresource(*args, **kwargs):
    try:
        yield None
    except:
        pass

class NullResource():
    def __enter__(self):
        return None
    def __exit__(self, *args, **kwargs):
        return True

with nullresource() as r:
    r.some_method()

with NullResource() as r:
    r.some_method()

Не понимаю как работает контекстный менеджер. Можете объяснить, как исполнится пример кода и почему именно так?


Ответы (1 шт):

Автор решения: eri

yeild прерывает функцию возвращая значение None. Эта часть аналог __enter__, тутошнее None присваивается к r.

Потом выполняется тело блока with. В этой Там возникает ошибка None object has no attribute 'some_method' потому что some_method нигде не определен.

Это исключение попадает в блок except и там игнорируется.

Во втором случае __enter__ присваивает значение r, а __exit__ выполняется при выходе из блока with.

Исключение возникшее в блоке передается в метод .__exit__(self, exc_type, exc_value, traceback) в аргументах и там никак не обрабатывется в вашем случае.

Правильный код:

from contextlib import contextmanager

@contextmanager
def nullresource(*args, **kwargs):
    def somemethod():
        print('somemethod')
    try:
        yield somemethod
    except Exception as e:
        print('произошла непредвиденная ошибка')
        raise e

with nullresource() as r_some_method:
    r_some_method()

и с классом

class NullResource():
    def some_method(self):
        print('NullResource().some_method()')

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            print('произошла непредвиденная ошибка')

with NullResource() as r:
    r.some_method()
→ Ссылка