Главная Веб-разработка Как отладить код – Отладка кода для начинающих – Tproger

Как отладить код – Отладка кода для начинающих – Tproger

от admin

Покажем, как отладить сложный код просто и без паники. Поговорим о ключевых инструментах и дадим советы, которые помогут даже начинающим разработчикам быстро найти проблему.

012 открытий64 показов

В 2017 году Amazon потерял сотни миллионов долларов из-за одной опечатки.

Сбой длился 4 часа и привёл к сбою в работе Netflix, Airbnb и даже Комиссии по ценным бумагам и биржам США. А виной всему человеческий фактор: сотрудник занимался рутинной отладкой системы, ошибся в команде и отключил сервера, которые отключать было нельзя.

Да, относиться к отладке кода нужно не менее внимательно, чем к его написанию. Поэтому сегодня мы покажем, как отладить сложный код просто и без паники. Поговорим о ключевых инструментах и дадим советы, которые помогут даже начинающим разработчикам быстро найти проблему.

Так отлаживать или дебажить?

Дебажить –– англицизм, который значит то же самое. Используйте тот термин, который вам нравится. А мы будем их чередовать.

Итак, отладка — процесс выявления и исправления ошибок в программном коде.

Ошибки бывают разные:

Синтаксические

Синтаксическая ошибка –– это, например, забытая закрывающаяся скобка или пропущенный отступ.

Здесь синтаксическая ошибка в том, что мы забыли двоеточие в первой строке:

			def add(a, b) #ошибка тут, мы забыли двоеточие     return a + b 		

В Python обязательно нужно ставить двоеточие после объявления функции. Без этого язык не поймет, что за двоеточием следует тело функции. Поэтому программа выполнена не будет.

Топ пакетов для улучшения работы с Pythontproger.ru

Как правильно:

			def add(a, b):     return a + b 		

Логические

Логические ошибки –– неправильная логика программы. Код может выполняться без проблем в синтаксисе и не выбрасывать исключения, но при этом не давать ожидаемого результата. Такие ошибки трудно отследить, потому что Python не сообщает о них явно.

Допустим, мы пишем программу для проверки чётности:

			def is_even(number):     return number % 2 == 1  # Здесь логическая ошибка  print(is_even(4))  # Ожидаем True, но получаем False 		

Вместо проверки number % 2 == 0 проверяется number % 2 == 1. Это логическая ошибка.

Исключения

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

Разберём деление на ноль. Это действие вызовет исключение ZeroDivisionError:

			def divide(a, b):     return a / b  print(divide(10, 0)) 		
			ZeroDivisionError: division by zero 		

Такие исключения можно обрабатывать, чтобы программа не упала. Используем try-except:

			def divide(a, b):     try:         return a / b     except ZeroDivisionError:         return "no division by zero in this house!"  print(divide(10, 0)) 		

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

Перейдём к инструкции по отладке.

Шаг 1: Анализируем ошибки и логи

Перед тем, как отлаживать код, важно понять: что именно пошло не так? Поэтому первый шаг –– анализ.

Типы ошибок мы уже разобрали, поэтому будет полегче. Иногда их не получается увидеть сразу в коде –– если бы всё было так просто! Тогда на помощь приходят логи, которые предоставляет программа или ваша IDE.

Что с ними делать:

  1. Изучите сообщение об ошибке. Важно понять, где и почему произошёл сбой. Обычно сообщение указывает тип ошибки и место, где она возникла. Мы уже видели такое поведение в предыдущем разделе, когда забыли поставить двоеточие;
  2. Проверьте логи. В логах будут важные данные об ошибке. Обратите внимание на ключевые слова: Error или Exception;
  3. Воспроизведите ошибку. Попробуйте выполнить код несколько раз. Возможно, это был случайный баг, который больше не повторится.

Как отладить код - Отладка кода для начинающих - Tproger

Шаг 2: Разделяем задачу на более мелкие части

Сломанный код лучше разбить на более мелкие и понятные части. Это поможет вам найти ошибку быстрее, так как вы точно определите, где её точно нет.

Как это работает:

Если ошибка возникает в сложном фрагменте, то лучше разделить его на более мелкие шаги.

Пример: Если программа загружает файл, обрабатывает данные и записывает результат, проверьте отдельно каждую функцию:

  • Загружается ли файл?
  • Обработались ли данные?
  • Успешно ли записывается результат?

Также можно сузить область поиска ошибки. Если задача большая, начните с проверки небольших фрагментов кода, чтобы изолировать проблемный участок. Загоните ошибку в угол.

Это лучше, чем хаотично бросаться то в одну, то в другую часть кода и искать иголку в стоге сена.

Шаг 3: Воссоздаём проблему

Репродукция ошибки — самая важная задача. Чтобы понять, как исправить ошибку, вам нужно её увидеть и поймать. Иногда она проявляется только при определенных условиях, а при каких –– неясно.

Тут стоит схитрить:

  • Попробуйте воспроизвести ошибку при разных входных данных. Может быть, строка не ломает программу, а число –– да;
  • Пользуйтесь инструментами отладки и отслеживайте каждый шаг программы.

И тут мы подобрались к самому интересному. Пока что мы говорили о том, как решать проблему. Но не упомянули, с помощью чего. Исправляемся.

Отладчики и логирование

Отладчики встроены в большинство IDE. Например, в PyCharm или Visual Studio есть встроенные отладчики, с помощью которых можно поставить точки останова.

Точка останова (breakpoint) — инструмент, с помощью которого вы можете остановить программу на определенном этапе и изучить её состояние. Например, проверить, какие значения принимают переменные или что именно происходит перед вызовом ошибки.

Как это работает:

  1. Установите точку останова в нужной строке;
  2. Запустите программу в режиме отладки;
  3. Выполнение остановится на этой строке: изучите текущие данные.

Разберём на примере Visual Studio:

Напишем небольшую функцию, в которой рассчитывается площадь прямоугольника:

			def main():    width = 5    height = 10    result = width * height    print(f"Площадь: {result}")  main() 		

Поставим точки останова на переменных width, height и result:

Читать также:
Программируем робота и настраиваем управление: 2-я часть гайда по сборке робота

Как отладить код - Отладка кода для начинающих - Tproger

Перейдём вот в эту панельку:

Как отладить код - Отладка кода для начинающих - Tproger

И запустим дебаггинг:

Как отладить код - Отладка кода для начинающих - Tproger

После запуска в редакторе появится новая панелька –– для управления отладкой:

Как отладить код - Отладка кода для начинающих - Tproger

С помощью неё можно остановить или перезапустить отладку, перейти к следующей точке останова и так далее.

В панели слева появятся значения, за которыми мы следим:

Как отладить код - Отладка кода для начинающих - Tproger

Здесь вы можете увидеть, чему равна каждая переменная.

Напишем функцию с ошибкой, которую уже разбирали:

			def main():    colors = ['violet','beige', 'teal']    print(colors[4])  main() 		

Мы пытаемся получить элемент, индекс которого не существует. Красная плашка предупреждает, что возникло исключение:

Как отладить код - Отладка кода для начинающих - Tproger

List index out of range –– такого индекса в списке нет. Вроде всё понятно, но можно разобраться.

Сбоку мы видим список colors, его элементы и длину len(). В Python, как и во многих других языках, отсчёт начинается с 0. Если в списке 3 элемента, то индекс последнего –– 2. Поэтому мы и получаем ошибку.

Аналитик данных: обзор профессии и курса от MDStproger.ru

Помимо точек останова можно следить за стеком вызовов.

Стек вызовов — цепочка вызванных функций. Она показывает, что происходит на каждом шаге программы.

Это особенно важно при сложных ошибках, скрытых глубоко в коде. Перепишем немного и сделаем несколько программ:

			colors = ['violet', 'beige', 'teal']  def get_favorite_color(index):    return colors[index]   def display_favorite_color(index):    color = get_favorite_color(index)    print(f"Ваш любимый цвет: {color}")   def main():    display_favorite_color(4)   main() 		

Ошибка всё ещё на месте, но теперь её появление происходит не сразу в функции main, а глубже.

И стек вызовов нам показывает, что сначала выполняется main, затем display_favorite_color и уже потом get_favorite_color, где и живёт ошибка:

Как отладить код - Отладка кода для начинающих - Tproger

Эту проблему можно решить с помощью try-except. Советуем попробовать самостоятельно🙂.

И последний способ отладки, который разберём –– логирование. Можно использовать print() или модуль, который уже заботливо написали за нас. Результат одинаковый — вывод нужных данных в определённое время. Так мы поймём, что лежит в переменной и почему программа ломается.

Примеры с print мы уже разбирали в предыдущих шагах. Метод простой и лёгкий –– то, что нужно для новичков.

Разберём вариант посложнее с модулем logging. Его нужно импортировать и настроить:

			import logging #импорт  logging.basicConfig(level=logging.DEBUG, #строка 3 format='%(asctime)s - %(levelname)s - %(message)s', ) #настройка  def get_favorite_color(index):    logging.info("Получение цвета")    return colors[index]  def display_favorite_color(index):    color = get_favorite_color(index)    logging.debug(f"Ваш любимый цвет: {color}") def main():    display_favorite_color(2)  main() 		

Теперь подробнее про конфигурацию. В logging есть несколько типов сообщений:

  • Отладочные –– DEBUG. Они показывают подробности о значениях переменных или работе отдельных функций;
  • Информационные –– INFO. В них можно прописывать статусы выполнения программы;
  • Предупреждения –– WARNING. Сообщения с потенциальными проблемами;
  • Ошибки –– ERROR и CRITICAL. 

Мы указали, что хотим видеть все сообщения с помощью строки 3. Теперь в консоли будет отображаться все, что нужно: предупреждения, ошибки и обычные сообщения отладки.

А на следующей строке указываем, в каком формате хотим видеть сообщение. В итоге получаем точное время, тип сообщения и само сообщение:

Как отладить код - Отладка кода для начинающих - Tproger

Это намного удобнее, чем прописывать все данные в print вручную.

Если нам нужны только ворнинги, то меняем конфигурацию:

			logging.basicConfig(level=logging.WARNING) 		

Шаг 4: Тестируем — юнит-тесты и их роль

Когда речь идёт об отладке кода, нельзя забывать о тестах. Потому что они помогают выявить ошибки и опасные места на моменте разработки, когда их ещё легко заметить и поправить.

Юнит-тесты — отличный способ проверять, что каждый блок вашего кода работает как положено.

Они особенно полезны в отладке сложных программ и приложений, где ошибки могут проявляться только после нескольких шагов или при конкретных входных значениях. Например, при списках.

Для этого можно использовать pytest или unittest.

Давайте поработаем с pytest. Напишем в файле main.py очень простую функцию:

			def main(num):    return num ** 2 		

Функция принимает число и возвращает квадрат числа.

Напишем тест. Для этого нужно установить pytest в свою IDE и создать файлик. Например, test.py:

			from main import main  def test_main():    assert main(2) == 4 		

Наша гипотеза: 2 в квадрате равно 4. Для того, чтобы её проверить, используем assert.

Если в терминале запустить команду pytest test.py, то увидим, что всё прошло успешно:

Как отладить код - Отладка кода для начинающих - Tproger

Если же заменить 4 на 5, то тест упадёт. Так как 2 в квадрате –– не 5:

Как отладить код - Отладка кода для начинающих - Tproger

Советы по улучшению процесса отладки

Мы разобрались, как дебажить и тестировать код. Напоследок дадим три базовых совета, которые актуальны не только для Python, но и для любого языка программирования.

Делите код на небольшие модули

Разбивайте программу на маленькие независимые части. Так их легче тестировать и искать ошибки. Например, вместо одной огромной функции лучше написать несколько компактных. Каждая из них будет отвечать за конкретную задачу. Рефакторинг поможет упростить логику и предотвратить дублирование кода.

Пишите автоматические тесты

Автоматическое тестирование позволяет ловить ошибки на ранних этапах. Вы можете и не увидеть их сразу. Зато они вас видят.

Поэтому после написания каждой новой функции добавляйте тесты. Это избавит от сюрпризов в будущем, когда изменение одной программы неожиданно ломает другую.

Комментируйте код

Не забывайте комментировать код. Объяснять, зачем и как работает каждая функция. Комментарии помогут и вам, и вашей команде быстрее разобраться в коде, особенно спустя несколько месяцев.

Ну и конечно, называйте функции и переменные понятно. Не усложняйте жизнь себе и коллегам. То, что изначально сделано качественно и с умом, с меньшей вероятностью придётся дебажить.

Но если всё-таки пришлось, следуйте нашей инструкции, и всё обязательно получится.

Похожие статьи