Контекстные менеджеры: как работают и как написать свой
Вопрос
Что такое контекстный менеджер, как он работает и как написать свой двумя способами?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
`with` гарантирует освобождение ресурса даже при исключении
Протокол `__enter__`/`__exit__`, значение `as` из `__enter__`
`__exit__` получает исключение и может его подавить, вернув True
`@contextmanager` из генератора: до `yield` вход, после выход, `try/finally`
Примеры: файлы, блокировки, транзакции, временная смена настроек
Что могут спросить следом
- Как открыть заранее неизвестное число файлов?
- Чем
with open()лучшеf = open(); f.close()?
Разбор
Образцовый ответ: «Контекстный менеджер это объект, который with использует, чтобы выполнить подготовку и гарантированную очистку. На входе вызывается __enter__, его результат попадает в переменную после as. На выходе, даже если внутри было исключение или return, вызывается __exit__ с типом, объектом и traceback исключения; если он вернёт истину, исключение подавляется, обычно возвращают None. Первый способ написать свой: класс с этими двумя методами, например таймер или временная смена рабочей директории. Второй короче: генератор с декоратором contextlib.contextmanager, где код до yield это вход, значение yield идёт в as, а код после yield это выход, и его обязательно оборачивают в try/finally. Применения: файлы, блокировки threading.Lock, транзакции БД, соединения. Для динамического числа ресурсов есть ExitStack, для асинхронного кода async with и asynccontextmanager».
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.