Короткий ответ
__exit__(exc_type, exc_val, exc_tb) получает информацию об исключении из блока with; если возвращает True, исключение считается подавленным и не распространяется дальше, а если False/None — пробрасывается как обычно.
Как это работает подробнее
Python вызывает __exit__ при любом выходе из блока with — и при нормальном завершении (все три аргумента None), и при исключении. Возвращаемое значение определяет, «поглощается» ли исключение менеджером или пробрасывается наружу.
Пример кода
example-263.py
class SuppressValueError:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is ValueError:
print(f"Подавлено: {exc_val}")
return True # исключение поглощено
return False # остальные исключения пробрасываются дальше
with SuppressValueError():
raise ValueError("ожидаемая ошибка")
print("Выполнение продолжилось") # этот код выполнится
with SuppressValueError():
raise TypeError("неожиданная ошибка") # не подавляется, пробрасывается наружуЧто использовать на практике
- Практика. Подавление исключений в
__exit__стоит делать осознанно и редко — например, для специфичных ожидаемых исключений, иначе баги в коде пользователя будут незаметно «тонуть» внутри менеджера.contextlib.suppress— готовый пример такого осознанного подавления.
Подводные камни
- Риски. Случайно возвращают truthy-значение из
__exit__(забывают явныйreturn None/False), из-за чего реальные ошибки в коде приложения перестают доходить до вызывающего кода и тестов.