Знаете, что самое опасное в проде на Python? Когда кто-то говорит:

«Да там всё просто работает».

На старте кажется норм: сервис не падает, пользователи довольны. Но на практике это один из самых тихих способов убить систему. Особенно если речь идёт о except Exception.

Python — мягкий язык. Он позволяет коду жить, даже когда логика трещит по швам. И именно поэтому статус «просто работает» в Python-продакшене — не стабильность, а предвестник скрытых проблем.

Первый раз, когда я это понял

У нас был микросервис, который обрабатывал данные пользователей для аналитики. Всё вроде ок: деплой прошёл, тесты зелёные, метрики в норме. Но через пару недель начали приходить жалобы на отчёты — цифры не сходились.

Я полез в код и увидел это:

try:
    value = int(data.get("amount"))
except Exception:
    value = 0

На первый взгляд вроде безопасно. Но кто-то прислал data = {"amount": "12.5"}. Python бросил ValueError, но блок except Exception поймал всё и вернул 0.

Результат: неделя отчётов с неверными данными. Сервис не упал, тесты не сломались, а данные были испорчены.
Я помню, как в тот день подумал:

«Блять, из-за одной строчки весь пайплайн сгорел, а мы даже не заметили!»

И это был только первый звонок.

Почему except Exception в Python — тихий убийца

Python перехватывает всё подряд. Один блок except Exception — и вы ловите:

  • ошибки логики,

  • ошибки данных,

  • сбои внешних сервисов,

  • баги других разработчиков.

И всё это выглядит одинаково: сервис работает, тесты проходят, метрики зелёные. Но реальность такая: ты больше не знаешь, что реально происходит.

Когда «работает» превращается в проблему

Пример 1. Дефолтные значения

def is_enabled(config):
    try:
        return bool(config.get("enabled", True))
    except Exception:
        return False

Вроде бы безопасно. А вот что реально происходит:

{"enabled": "false"}  # True — WTF!
{"enabled": 0}        # False
{"enabled": None}     # False

Сервис молчит, логи зелёные, тесты проходят. Но фича ведёт себя странно.
И только когда пользователи начинают жаловаться, становится понятно, что код фактически сломал логику, но «не сломался».

Пример 2. Ошибки внешних сервисов

try:
    result = external_api_call(data)
except Exception:
    result = None

Сервис не падает, пользователи ничего не замечают, лог говорит «всё ок».

Но реальная проблема: external_api_call вернул некорректные данные. Они пошли дальше по цепочке, испортили расчёты и логирование.

Через день аналитики заметили странные отчёты. И да — исключение было поймано, а данные уже «сгорели».

Пример 3. Потеря контекста

Иногда блоки except Exception копятся по всему проекту. И вот результат:

try:
    do_step1()
except Exception:
    pass

try:
    do_step2()
except Exception:
    pass

Каждый шаг молча «теряет» ошибки. В итоге:

  • новые разработчики боятся трогать код,

  • code review превращается в гадание «что сломается, если я это поменяю?»,

  • рефакторинг — минное поле.

И это не гипотетически, а на живом проде, где один неправильный фикс может испортить аналитические отчёты на месяц.

Почему баги живут годами

  1. Исключение уже обработано → стек-трейс потерян.

  2. Лог не выглядит опасно → никто не ищет причину.

  3. Поведение «плавает» → воспроизвести сложно.

  4. Система работает → создаётся иллюзия стабильности.

И это настоящий кошмар для команды: сервис вроде жив, а доверие к нему улетает в трубу.

Тесты не спасают

  • проверяют только happy path;

  • мокают внешние зависимости;

  • не учитывают «странные» данные;

  • не проверяют цепочки вызовов через несколько сервисов.

Всё, что скрывается под except Exception, тесты не видят. Ты думаешь, что всё ок, а на деле половина данных неверна, а логика сломана.

Как жить с этим в Python

Статья не про запрет except Exception. Она про осознанное использование:

  • ловить только конкретные исключения, а не всё подряд;

  • логировать ошибки с полным контекстом;

  • валидировать входные данные перед обработкой;

  • позволять сервису падать там, где это безопасно, чтобы баги не копились;

  • добавлять юнит-тесты с нестандартными кейсами, чтобы ловить «странные» данные.

Вывод

В Python «просто работает» — это не стабильность.
Это тихий враг, который делает код живым, но непредсказуемым.

Он маскирует ошибки, разрушает доверие и усложняет поддержку.

Если вы поймёте, что не можете объяснить, почему код работает, — это отличный повод остановиться, разобраться и перестать надеяться на чудо.