Исключения и отладка: вопросы для собеседования (часть 4)

try/except, raise, типы исключений, отладка с pdb — на собеседовании спрашивают, как обрабатывать ошибки и что происходит при необработанном исключении. Просят объяснить разницу между ValueError и TypeError, показать try/except/finally. Грамотная обработка ошибок отличает продакшн-код от скрипта в Jupyter.

Коллекции и структуры данныхГенераторы списков и встроенные функцииЦиклы и условияРабота с файлами: JSON и CSVФункции и аргументыИтераторы и генераторыNumPy: основыPandas и DataFrameСинтаксис и типы данных

Вопросы 1620 из 20

16Вы пишете функцию для расчёта метрики и понимаете, что без обязательного поля `user_id` результат будет неверным. Что лучше сделать, чтобы не «тихо» считать мусор и облегчить отладку?
AВернуть 0 и продолжить, чтобы дашборд не «краснел».
BВернуть `None` без объяснений, чтобы ошибка «не мешала».
CНапечатать сообщение через `print` и продолжить выполнение.
DПоднять явную ошибку, например `raise ValueError('user_id is required')`.
Ответ: Если без данных метрика бессмысленна, лучше явно остановиться через `raise`, чем скрывать проблему.

Возврат «заглушек» вроде 0 или `None` может незаметно испортить отчёт и сделать проблему трудноуловимой. Если поле обязательно, это нарушение контракта входных данных, и правильнее явно сигнализировать через `raise`. Так ошибка быстро обнаруживается, а traceback помогает найти источник некорректных данных.

17Вы поймали ошибку, залогировали её и хотите пробросить дальше, чтобы пайплайн упал и traceback сохранился. Что нужно сделать внутри `except`?
AСделать `return None`, чтобы ошибка не мешала.
BСделать `pass`, чтобы продолжить выполнение.
CСделать `raise Exception('error')`, чтобы «перезаписать» ошибку.
DСделать просто `raise`, чтобы перекинуть то же исключение дальше.
Ответ: Внутри `except` команда `raise` без аргументов перекидывает текущее исключение дальше.

Если ошибка не является ожидаемой и не должна быть «исправлена» на месте, лучше её не скрывать. `raise` без аргументов сохраняет оригинальный тип исключения и его traceback, что сильно облегчает отладку. Если вместо этого поднять новое исключение без контекста, можно потерять важные детали о первопричине.

18Поле `age_text` приходит как строка и может быть `"18"`, `""` или `"N/A"`. Вы хотите получить число или `None`, не скрывая неожиданные баги. Какой подход наиболее практичный в прикладной аналитике без регулярных выражений?
AВсегда делать `int(age_text)` без проверок и не ловить исключения.
BСначала сделать `s = age_text.strip()`, затем если `s.isdigit()` — `int(s)`, иначе вернуть `None`.
CДелать `float(age_text)` и округлять всегда.
DИспользовать `eval(age_text)` и считать, что данные безопасны.
Ответ: Иногда лучше предварительная проверка (например, `strip` + `isdigit`), чем массовый `try`/`except`.

Сравнивайте подходы: (1) обработка через исключения и (2) проверка условий. Если формат простой (цифры или пусто), проверка через `strip()` и `isdigit()` делает поведение явным и уменьшает количество исключений в потоке. При этом неожиданные случаи можно логировать отдельно, а не скрывать через слишком широкий `except`.

19В `try` произошла ошибка, а в `finally` тоже случилось исключение (например, при закрытии ресурса). Почему это плохо с точки зрения отладки?
AПлохо только из-за производительности, но на отладку это не влияет.
BНичего страшного: исключение из `finally` автоматически игнорируется.
CИсключение из `finally` может «перекрыть» исходную ошибку, и станет сложнее понять первопричину по traceback.
DЭто хорошо: вы увидите сразу два traceback, и отладка станет проще.
Ответ: Если `finally` падает, он может скрыть исходную причину падения и усложнить диагностику.

`finally` нужен для безопасной уборки. Если в нём есть код, который может упасть, вы рискуете потерять фокус на исходном исключении из `try`. В результате вместо первопричины в логах может доминировать ошибка из `finally`, и исправление станет дольше и дороже.

20Вы пишете функцию `def get_user(user_id): ...` и ожидаете, что `user_id` — число. Если кто-то передал строку `'42'`, какое исключение обычно уместнее поднять, чтобы явно сообщить о неверном типе входных данных?
AСделать `raise ValueError('bad type')`.
BСделать `raise TypeError('user_id must be int')`.
CСделать `raise KeyError('user_id')`.
DСделать `raise IndexError('user_id')`.
Ответ: Неверный тип аргумента — частый случай для `TypeError`; неверное значение при корректном типе — для `ValueError`.

Разделяйте причины ошибок: если аргумент пришёл не того типа (строка вместо числа), это проблема типов и уместен `TypeError`. Если тип правильный, но значение недопустимо (например, отрицательное число там, где нельзя), часто используют `ValueError`. Такая дисциплина улучшает диагностику и делает обработку ошибок предсказуемой.

1234

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать в Telegram

Другие темы: Python

Коллекции и структуры данныхГенераторы списков и встроенные функцииЦиклы и условияРабота с файлами: JSON и CSVФункции и аргументыИтераторы и генераторыNumPy: основыPandas и DataFrameСинтаксис и типы данных