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

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

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

Вопросы 1115 из 20

11Вы пишете функцию, которая внутри `try` делает `return`, а в `finally` закрывает ресурс (например, файл или соединение). Что произойдёт с кодом в `finally` при `return` из `try`?
AКод в `finally` всё равно выполнится перед выходом из функции.
BКод в `finally` не выполнится, потому что сработал `return`.
CКод в `finally` выполнится только если в `try` было исключение.
DКод в `finally` выполнится только если `return` возвращает `None`.
Ответ: `finally` выполняется даже при `return`, поэтому подходит для освобождения ресурсов.

Одна из причин использовать `finally` — гарантировать уборку ресурсов независимо от пути выполнения. Даже если внутри `try` был `return`, интерпретатор всё равно сначала выполнит `finally`, а потом завершит функцию. Это важно для предотвращения утечек файловых дескрипторов и соединений.

12После запроса в базу вы получаете список `rows`, который иногда бывает пустым. Код `rows[0]` падает с `IndexError`. Какой вариант лучше, если пустой результат — ожидаемый кейс?
AОбернуть всё в `try` и ловить `except Exception:`.
BСделать проверку `if rows:` перед `rows[0]`, иначе вернуть `None` или обработать пустой кейс отдельно.
CПисать `rows[0]` и игнорировать `IndexError`, потому что он «не важен».
DСделать `raise IndexError('no rows')`, чтобы всегда падало.
Ответ: Если пустой список возможен по данным, лучше явная проверка, чем ловля ошибок «на всякий случай».

Сравнение подходов важно: проверка условия делает код понятнее, а исключения — инструмент для неожиданных ситуаций. Если пустой результат нормален, `if rows:` заранее описывает логику, помогает читателю кода и убирает лишние исключения из потока. Ловить `Exception` слишком широко — риск скрыть реальные баги.

13Вы преобразуете поле из CSV: `price = int(text)`. Иногда там встречается `N/A`. Какой вариант обработки ошибки лучше соответствует цели «точечный `except` (не ловить всё подряд)»?
AИспользовать `except Exception:` и в нём просто ставить `price = 0`.
BИспользовать `except ValueError:` и обработать только ожидаемую ошибку конвертации.
CИспользовать `except:` и в нём делать `pass`.
DНе использовать `try`/`except`, пусть скрипт падает всегда, даже если это ожидаемо.
Ответ: Ловите ожидаемые исключения конкретных типов, например `ValueError` при `int(...)`.

В аналитических пайплайнах часть ошибок ожидаема: например, плохие значения в полях. Но ловить всё подряд (`except Exception:`) опасно — можно скрыть баги в коде. Правильнее ловить конкретное исключение (`ValueError` для некорректного значения), чтобы обработка была контролируемой и отладка — проще.

14Вы обрабатываете события, где поле `utm_source` может отсутствовать, и это нормально. Какой подход обычно лучше, чем ловить `KeyError` ради значения по умолчанию?
AИспользовать `event.get('utm_source', 'unknown')`, чтобы получить дефолт без исключения.
BВсегда делать `event['utm_source']` и оборачивать весь пайплайн в `except Exception:`.
CПринудительно превращать событие в строку через `str(event)` и искать подстроку.
DИспользовать `raise KeyError('utm_source')`, чтобы заполнить дефолт.
Ответ: Если отсутствие ключа ожидаемо, удобнее `dict.get(...)`, чем `try`/`except KeyError`.

Исключения подходят для действительно исключительных ситуаций. Если поле может отсутствовать по данным, `event.get('utm_source', 'unknown')` делает намерение ясным, упрощает код и уменьшает «шум» в отладке. `KeyError` полезен, когда ключ обязан быть и его отсутствие — ошибка контракта.

15В коде есть два обработчика: `except ValueError:` и `except Exception:`. Почему порядок этих блоков `except` важен?
AПорядок не важен: Python всё равно выберет самый подходящий `except`.
B`except Exception:` должен идти первым, чтобы «ускорить» обработку ошибок.
CБолее специфичные исключения (например, `ValueError`) должны идти раньше, иначе их перехватит более общий `except Exception:`.
DПорядок зависит только от версии Python и не имеет смысла.
Ответ: Сначала пишут специфичные `except`, потом более общие, иначе логика обработки ломается.

Python проверяет блоки `except` сверху вниз. Если поставить `except Exception:` раньше, он перехватит почти всё и до `except ValueError:` дело не дойдёт. Это ухудшает диагностику и приводит к неправильной обработке ошибок — нарушается цель «точечных `except`».

1234

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

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

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

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

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