Drone X

Ошибки, валидация и отладка

4 блок(ов) теории · 10 заданий · 150 баллов

Надёжная программа рассчитана не только на удачные данные: телеметрия приходит с мусорными строками, в журнале попадаются пропуски, деление иногда получает ноль, а индекс — значение за границей списка. Когда Python не может выполнить операцию, он выбрасывает исключение — значение особого рода, у которого есть тип и сообщение: тип называет класс проблемы, сообщение — конкретного виновника. Не перехваченное исключение останавливает программу и печатает traceback — отчёт о падении, который читают снизу вверх. Строки cells = int(raw) с сырым напряжением "22.2V" хватило, чтобы программа упала, и traceback рассказал всё: последняя строка ValueError: invalid literal for int() with base 10: '22.2V' — тип и сообщение, «что сломалось»; над ней — File "log.py", line 2 и сама строка кода — «где сломалось»; ещё выше перечислены вызовы, которые привели сюда, — «как мы попали». Классов проблем немного, и каждый стоит узнать в лицо. ValueError — значение неподходящего вида для операции, которая сама по себе возможна: int("abc"), float("abc"), int("3.5") (дробная запись не станет целым). ZeroDivisionError — деление на ноль: 1 / 0. TypeError — сама операция неприменима к таким значениям: строку "a" нельзя складывать с числом 1. KeyError — чтение словаря по отсутствующему ключу: spec["gps"] из модуля 5. IndexError — чтение списка по индексу за границей: [10, 16][5] — у списка из двух элементов есть только индексы 0 и 1 (модуль 4). Разница тонкая, но важная: ValueError — «не то значение», TypeError — «не те типы».

Падение — не единственный исход: рискованный участок оборачивают конструкцией try / except. В блоке try записывают операцию, которая может упасть, в except с указанием типа — что делать, если поднялось именно это исключение: try: return a / b, а следом except ZeroDivisionError: return None. Конкретный тип в except — правило гигиены: перехвачено будет только своё исключение, а чужие баги дойдут до поверхности и будут видны. Вернуть None — мягкий отказ: вызывающий сам решает, что делать, и проверяет результат через if result is None. Жёсткий отказ — бросить своё исключение оператором raise: raise ValueError("понятное сообщение") останавливает выполнение и печатает traceback с человеческим текстом вместо технического. raise внутри except заменяет техническую ошибку понятной: тип остаётся ValueError, а сообщение называет плохой вход по имени. Вторая работа raise — защитные проверки, гварды: серия if <условие плохого входа>: raise ValueError(...) в начале функции, по одному на правило, — и return True в конце, если всё пройдено; порядок гвардов важен, сообщается первое нарушенное правило. Третий приём — очистка данных: цикл по строкам с try: float(line) и except ValueError: continue — мусор пропущен, числа собраны. Пригодится и оператор in в новой роли: он проверяет не только ключи словаря и подстроки, но и принадлежность набору — cells in (1, 2, 3, 4, 6) отвечает на вопрос, есть ли число банок среди стандартных конфигураций.

Задания

0/10 заданий · 0/150 баллов

1. Три ситуации: ValueError, except: pass, деление на ноль

10 балл(ов)

Из бортового журнала три ситуации: разбор конфига наткнулся на int("abc"); оператор заглушил ошибку через except: pass; в расчёте встретилось 1 / 0 без обработки. Выберите вариант, где верно назван тип исключения int("abc"), объяснено, почему except: pass — антипаттерн, и сказано, что произойдёт при делении на ноль без обработки.

1 / 10