Поиск и исправление ошибок в коде на Python: Отладка с помощью IDLE

Оглавление

Все совершают ошибки — даже опытные профессиональные разработчики! Интерактивный интерпретатор Python, IDLE, довольно хорошо отлавливает такие ошибки, как синтаксические и ошибки во время выполнения, но есть ошибки третьего типа, с которыми вы, возможно, уже сталкивались. Логические ошибки возникает, когда в остальном корректная программа не выполняет то, что было задумано. Логические ошибки вызывают непредвиденное поведение, называемое ошибками. Устранение ошибок называется отладкой.

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

В этом руководстве вы узнаете:

  • Узнайте, как использовать Элемент управления отладкой IDLE окно
  • Потренируйтесь отлаживать работу с ошибочной функцией
  • Изучите альтернативные методы отладки вашего кода

Примечание: Это руководство адаптировано из главы “Поиск и исправление ошибок в коде” в Основы Python: Практическое введение в Python 3.

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

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

Основным интерфейсом отладчика IDLE является окно управления отладкой, или сокращенно окно отладки. Вы можете открыть окно отладки, выбрав Отладка→Отладчик в меню интерактивного окна. Продолжайте и откройте окно отладки.

Примечание: Если в строке меню отсутствует меню отладки, обязательно наведите фокус на интерактивное окно, щелкнув по нему.

Всякий раз, когда открыто окно отладки, в интерактивном окне отображается [DEBUG ON] рядом с приглашением, указывающим на то, что отладчик открыт. Теперь откройте новое окно редактора и расположите три окна на своем экране так, чтобы вы могли видеть их все одновременно.

В этом разделе вы узнаете, как устроено окно отладки, как пошагово просматривать код с помощью отладчика по одной строке за раз и как устанавливать точки останова, чтобы ускорить процесс отладки.

Окно управления отладкой: Краткий обзор

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

 1for i in range(1, 4):
 2    j = i * 2
 3    print(f"i is {i} and j is {j}")


Сохраните файл, затем оставьте окно отладки открытым и нажмите F5. Вы заметите, что выполнение не продвинулось слишком далеко.

Окно отладки будет выглядеть следующим образом:

Image of IDLE's Debug window

Обратите внимание, что панель стека в верхней части окна содержит следующее сообщение:

> '__main__'.<module>(), line 1: for i in range(1, 4):


Это говорит о том, что строка 1 (которая содержит код for i in range(1, 4):) должна быть запущена примерно, но еще не началось. Часть сообщения '__main__'.module() указывает на то, что в данный момент вы находитесь в главном разделе программы, а не, например, в определении функции до того, как будет достигнут основной блок кода.

Под панелью Stack находится панель Locals, в которой перечислены некоторые странно выглядящие элементы, такие как __annotations__, __builtins__, __doc__, и так далее. Это внутренние системные переменные, которые вы можете пока игнорировать. Во время выполнения вашей программы вы увидите переменные, объявленные в коде, отображаемом в этом окне, чтобы вы могли отслеживать их значение.

В верхнем левом углу окна отладки расположены пять кнопок: Перейти, Шаг, Снова, Выйдите из и Выйдите из. Эти кнопки управляют тем, как отладчик перемещается по вашему коду.

В следующих разделах вы узнаете, что делает каждая из этих кнопок, начиная с шага .

Кнопка "Шаг"

Далее нажмите Шаг в верхнем левом углу окна отладки. Окно отладки немного изменится и будет выглядеть следующим образом:

Python IDLE Step button

Здесь следует обратить внимание на два отличия. Во-первых, сообщение на панели стека меняется на следующее:

> '__main__'.<module>(), line 2: j = i * 2:


На этом этапе строка 1 вашего кода выполнена, и отладчик остановился непосредственно перед выполнением строки 2.

Второе изменение, на которое следует обратить внимание, - это новая переменная i, которой присвоено значение 1 на панели Locals. Это потому, что for цикл в первой строке кода создал переменную i и присвоил ей значение 1.

Продолжайте нажимать кнопку Шаг, чтобы построчно просмотреть свой код и посмотреть, что происходит в окне отладчика. Когда вы дойдете до строки print(f"i is {i} and j is {j}"), вы сможете увидеть выходные данные, отображаемые в интерактивном окне по одному фрагменту за раз.

Что еще более важно, вы можете отслеживать увеличение значений i и j по мере прохождения цикла for. Вы, вероятно, можете себе представить, насколько полезна эта функция при поиске источника ошибок в ваших программах. Знание значения каждой переменной в каждой строке кода может помочь вам точно определить, где что-то пошло не так.

Точки останова и кнопка Перехода

Часто вы можете знать, что ошибка должна быть в определенном разделе вашего кода, но вы можете не знать точно, где именно. Вместо того чтобы нажимать кнопку Шаг в течение всего дня, вы можете установить точку останова , которая указывает отладчику непрерывно запускать весь код, пока он не достигнет точки останова.

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

Чтобы задать точку останова, щелкните правой кнопкой мыши (Ctrl-щелчок на компьютере Mac) строку кода в окне редактора, на которой вы хотели бы сделать паузу, и выберите Установите точку останова. IDLE выделяет строку желтым цветом, указывая, что ваша точка останова установлена. Чтобы удалить точку останова, щелкните правой кнопкой мыши на строке с точкой останова и выберите Очистить точку останова.

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

Установите точку останова в строке кода с помощью инструкции print(). Теперь окно редактора должно выглядеть следующим образом:

Python IDLE breakpoint pt. 1

Сохраните и запустите файл. Как и ранее, панель стека в окне отладки показывает, что отладчик запущен и ожидает выполнения строки 1. Нажмите Перейти и посмотрите, что произойдет в окне отладки:

Python IDLE Go button pt. 1

На панели стека теперь отображается следующее сообщение, указывающее на то, что оно ожидает выполнения строки 3:

> '__main__'.<module>(), line 3: print(f"i is {i} and j is {j}")


Если вы посмотрите на панель Locals, то увидите, что обе переменные i и j имеют значения 1 и 2 соответственно. Нажав Перейти, вы дали команду отладчику непрерывно запускать ваш код, пока он не достигнет либо точки останова, либо завершения программы. Нажмите Перейти еще раз. Окно отладки теперь выглядит следующим образом:

Python IDLE Go button pt. 2

Вы видите, что изменилось? На панели стека отображается то же сообщение, что и раньше, указывающее на то, что отладчик ожидает повторного выполнения строки 3. Однако значения переменных i и j теперь равны 2 и 4. В интерактивном окне также отображаются выходные данные первого запуска строки с print() в цикле.

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

Нажмите Перейти в третий раз. Теперь i и j имеют значения 3 и 6. Как вы думаете, что произойдет, когда вы нажмете Перейти еще раз? Поскольку цикл for выполняется только три раза, при повторном нажатии Перейти выполнение программы завершится.

Снова и снова

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

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

В следующем разделе вы рассмотрите некоторые ошибки в коде и узнаете, как исправить их с помощью IDLE.

Раздавите несколько жучков

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

Следующий код определяет функцию add_underscores(), которая принимает единственный строковый объект word в качестве аргумента и возвращает новую строку, содержащую копию word, каждый символ которой заключен в подчеркивание. Например, add_underscores("python") должно возвращать "_p_y_t_h_o_n_".

Вот код ошибки:

def add_underscores(word):
    new_word = "_"
    for i in range(len(word)):
        new_word = word[i] + "_"
    return new_word

phrase = "hello"
print(add_underscores(phrase))


Введите этот код в окне редактора, затем сохраните файл и нажмите F5, чтобы запустить программу. Ожидаемый результат - _h_e_l_l_o_, но вместо этого вы видите только o_, или букву "o", за которой следует один знак подчеркивания.

Если вы уже видите, в чем проблема с кодом, не просто устраняйте ее. Цель этого раздела - узнать, как использовать отладчик IDLE для выявления проблемы.

Если вы не видите, в чем проблема, не волнуйтесь! К концу этого раздела вы ее обнаружите и сможете идентифицировать аналогичные проблемы в других кодах, с которыми столкнетесь.

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

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

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

  1. Угадайте, в каком разделе кода может содержаться ошибка.
  2. Установите точку останова и проверьте код, просматривая раздел с ошибками по одной строке за раз, попутно отслеживая важные переменные.
  3. Определите строку кода, если таковая имеется, содержащую ошибку, и внесите изменения для решения проблемы.
  4. Повторяйте шаги 1-3 по мере необходимости, пока код не заработает должным образом.

Шаг 1: Сделайте предположение О Том, Где находится ошибка

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

Обратите внимание, что программа разделена на две отдельные части: определение функции (где определено значение add_underscores()) и основной блок кода, который определяет переменную phrase со значением "hello" а затем выводит результат вызова add_underscores(phrase).

Посмотрите на основной раздел:

phrase = "hello"
print(add_underscores(phrase))


Как вы думаете, проблема может быть в этом? Не похоже, правда? В этих двух строках кода все выглядит хорошо. Итак, проблема, должно быть, в определении функции:

def add_underscores(word):
    new_word = "_"
    for i in range(len(word)):
        new_word = word[i] + "_"
    return new_word


Первая строка кода внутри функции создает переменную new_word со значением "_". С этим у вас все в порядке, поэтому вы можете заключить, что проблема находится где-то в теле цикла for.

Шаг 2: Установите точку останова и проверьте код

Теперь, когда вы определили, где должна быть ошибка, установите точку останова в начале цикла for, чтобы вы могли точно отследить, что происходит внутри кода с помощью окна отладки:

Python IDLE breakpoint pt. 2

Откройте окно отладки и запустите файл. Выполнение по-прежнему приостанавливается на первой попавшейся строке, которая является определением функции.

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

Python IDLE Debug window pt. 1

На этом этапе выполнение кода приостанавливается непосредственно перед входом в цикл for в функции add_underscores(). Обратите внимание, что на панели Locals отображаются две локальные переменные, word и new_word. В настоящее время word имеет значение "hello", а new_word имеет значение "_", как и ожидалось.

Нажмите Шаг один раз, чтобы войти в цикл for. Окно отладки меняется, и на панели Locals отображается новая переменная i со значением 0:

Python IDLE Debug window pt. 2

i это счетчик, используемый в цикле for, и вы можете использовать его, чтобы отслеживать, на какую итерацию цикла for вы в данный момент смотрите.

Нажмите Шаг еще раз. Если вы посмотрите на панель Locals, то увидите, что переменная new_word приняла значение "h_":

Python IDLE Debug window pt. 3

Это неправильно. Первоначально new_word имело значение "_", а на второй итерации цикла for теперь оно должно иметь значение "_h_". Если вы нажмете Шаг еще несколько раз, то увидите, что для new_word будет установлено значение e_, затем l_ и так далее.

Шаг 3: Определите ошибку и попытайтесь ее исправить

Вывод, который вы можете сделать на этом этапе, заключается в том, что на каждой итерации цикла for new_word заменяется следующим символом в строке "hello" и завершающим символом подчеркивания. Поскольку внутри цикла for есть только одна строка кода, вы знаете, что проблема, должно быть, связана со следующим кодом:

new_word = word[i] + "_"


Посмотрите на строку повнимательнее. В нем содержится команда Python получить следующий символ из word, поставить в конце него знак подчеркивания и присвоить эту новую строку переменной new_word. Это именно то поведение, которое вы наблюдали, проходя через цикл for!

Чтобы устранить проблему, вам нужно указать Python, чтобы он объединил строку word[i] + "_" с существующим значением new_word. Нажмите Завершить в окне отладки, но пока не закрывайте окно. Откройте окно редактора и измените строку внутри цикла for на следующую:

new_word = new_word + word[i] + "_"


Шаг 4: Повторяйте шаги с 1 по 3, пока ошибка не исчезнет

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

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

You can only toggle the debugger when idle


Всегда обязательно нажимайте Перейти или Выйти после завершения сеанса отладки, а не просто закрывайте отладчик, иначе вы возможно, у меня возникнут проблемы с его повторным открытием. Чтобы избавиться от этой ошибки, вам придется закрыть и снова открыть IDLE.

Программа приостанавливается непосредственно перед входом в цикл for в add_underscores(). Нажимайте Шаг несколько раз и наблюдайте, что происходит с переменной new_word на каждой итерации. Успех! Все работает так, как ожидалось!

Ваша первая попытка исправить ошибку удалась, поэтому вам больше не нужно повторять шаги 1-3. Так будет не всегда. Иногда вам придется повторить процесс несколько раз, прежде чем вы исправите ошибку.

Альтернативные способы поиска ошибок

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

В подобных ситуациях вы можете использовать для отладки печати, чтобы найти ошибки в вашем коде. При отладке печати используется print() для отображения текста в консоли, который указывает, где выполняется программа и в каком состоянии находятся программные переменные в определенных точках кода.

Например, вместо отладки предыдущей программы с помощью окна отладки вы могли бы добавить следующую строку в конец цикла for в add_underscores():

print(f"i = {i}; new_word = {new_word}")


Измененный код тогда выглядел бы следующим образом:

def add_underscores(word):
    new_word = "_"
    for i in range(len(word)):
        new_word = word[i] + "_"
        print(f"i = {i}; new_word = {new_word}")
    return new_word

phrase = "hello"
print(add_underscores(phrase))


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

i = 0; new_word = h_
i = 1; new_word = e_
i = 2; new_word = l_
i = 3; new_word = l_
i = 4; new_word = o_
o_


Это показывает вам, каково значение new_word на каждой итерации цикла for. Последняя строка, содержащая всего один символ подчеркивания, является результатом выполнения print(add_underscore(phrase)) в конце программы.

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

Отладка с помощью печати работает, но имеет ряд недостатков по сравнению с отладкой с помощью отладчика. Во-первых, вам приходится запускать всю программу каждый раз, когда вы хотите проверить значения своих переменных. Это может быть огромной тратой времени по сравнению с использованием точек останова. Вы также должны не забыть удалить эти print() вызовы функций из вашего кода, когда закончите отладку!

Пример цикла в этом разделе может быть хорошим примером для иллюстрации процесса отладки, но это не лучший пример Кода на Python. Использование индекса i указывает на то, что, возможно, существует лучший способ написания цикла.

Один из способов улучшить этот цикл - выполнить прямую итерацию по символам в word. Вот один из способов сделать это:

def add_underscores(word):
    new_word = "_"
    for letter in word:
        new_word = new_word + letter + "_"
    return new_word


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

Заключение: Отладка Python с помощью IDLE

Вот и все! Теперь вы знаете все об отладке с помощью окна отладки IDLE. Вы можете использовать основные принципы, которые вы использовали здесь, с различными инструментами отладки. Теперь вы хорошо подготовлены к тому, чтобы приступить к отладке вашего кода на Python.

В этом уроке вы узнали:

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

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

  1. Угадайте, где находится ошибка.
  2. Установите точку останова и проверьте код.
  3. Выявите ошибку и попытайтесь ее устранить.
  4. Повторяйте шаги с 1 по 3, пока ошибка не будет устранена.

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

Для получения дополнительной информации об отладке кода на Python ознакомьтесь с Отладка на Python с помощью Pdb. Если вам понравилось то, что вы узнали из этого примера из Основы Python: практическое введение в Python 3, тогда обязательно ознакомьтесь с остальной частью книги.

Back to Top