PythonJuniorTechnical
Что такое контекстный менеджер?
Context manager — объект с методами __enter__ и __exit__, который описывает захват и освобождение ресурса. with гарантирует вызов __exit__ даже при исключении, что нужно для файлов, lock, транзакций, временных патчей.
Что это и зачем
Context manager — объект, поддерживающий протокол __enter__ / __exit__. Конструкция with cm as x: гарантирует, что cleanup выполнится при выходе из блока: как при нормальном завершении, так и при исключении или break/return. Это решает ту же задачу, что try/finally, но локализует логику ресурса в одном месте.
Протокол
class FileLock:
def __init__(self, path):
self.path = path
self.fp = None
def __enter__(self):
self.fp = open(self.path, "w")
return self.fp # уходит в переменную после as
def __exit__(self, exc_type, exc_val, exc_tb):
if self.fp:
self.fp.close()
# вернуть True — подавить исключение, обычно возвращаем None (=False)
return False
with FileLock("data.txt") as f:
f.write("hello")
Типичные применения
- Файлы:
open(). - Локи:
threading.Lock,asyncio.Lock,multiprocessing.Lock. - Транзакции БД:
conn.cursor(),session.begin()в SQLAlchemy. - Сетевые сессии:
requests.Session(),aiohttp.ClientSession(). - Временные изменения:
decimal.localcontext(),unittest.mock.patch(). - Подавление:
contextlib.suppress(FileNotFoundError). - Несколько ресурсов:
contextlib.ExitStackдля динамического набора context manager-ов.
Async-вариант
class AsyncSession:
async def __aenter__(self):
self.session = await connect()
return self.session
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.session.close()
async with AsyncSession() as s:
await s.fetch("/api")
Подводные камни
- Открыть ресурс в
__init__, а не в__enter__— если объект создан, ноwithне выполнен, ресурс утечёт. - Возврат
Trueиз__exit__подавляет исключение, и часто это маскирует баги. - Многошаговый
__enter__без отката при ошибке в середине — нужен внутренний try/except, который освобождает то, что уже захвачено. - Использование
withдля объекта, у которого нет__enter__/__exit__, даётAttributeError: __enter__. - Смешивание sync (
__enter__) и async (__aenter__): asyncio ругается приwithна async-ресурсе.
Common mistakes
- Говорить только про файлы.
- Не объяснять exit при исключении.
- Не знать, что context manager может подавить исключение.
What the interviewer is testing
- Понимает управление ресурсами.
- Называет enter/exit.
- Умеет объяснить suppress behavior.