620 0 15 Alisher Alikulov

Python → Отладка Python кода в PyCharm (Debugging)

Отладка кода или Debugging - это поиск ошибок в коде и изучение как работает ваш код. 

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

Встроенный в PyCharm отладчик кода(Debugger) это очень удобный инструмент для понятия вашего кода. С помощью него вы сможете понять в каком порядке работает ваш код, какое значение у каждой переменной в каждый момент времени и в какой строчке происходит ошибка. 

И так, поехали.

Для примера возьмем простую функцию, которая принимает список чисел и суммирует только положительные из них. 

def sum_positive(values) -> int:
    result = 0
    for value in values:
        if value > 0:
            result =+ value

    return result


sum_of_all = sum_positive([1, 2, 3, -2, -4])

print(sum_of_all)

 

Откройте PyCharm. Создайто новый файл example1.py и скопируйте этот код в него. Запустите код нажав на Зеленую кнопку запуска в правом верхнем углу или нажав сочетание клавиш Ctrl+F10. 

Программа запустится успешно. И выдаст результат: 3

Но ведь сумма положительных чисел должна быть 6 для нашего списка! Что-то пошло не так, пора дебажжить код!

 

Запуск в режиме Debugging

Запускаем нашу программу в режиме Debugging. Для этого нужно нажать кнопку с зеленым жуком на панели или нажать сочетание клавиш Ctrl+F9. 

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

Connected to pydev debugger (build 231.9225.15)
3

Например вы увидите что-то такое. Это значит что код был запущен с подключенным дебаггером. Но что-то мы ничего нового не узнали о нашей программе. 

 

Точки останова или Breakpoints

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

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

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

Давайте мы поставим брейкпоинт на первой строке нашей функции, чтобы понять как работает функция с самого начала.

И запустим нашу программу в режиме дебага.

 

Интерфейс Дебаггера

Наконец-то мы дошли до этого момента. После запуска ваша программа остановит свое выполнение именно на этой точке. И мы увидим в PyCharm вот такое состояние:

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

А внизу у нас будет окно Дебаггера, в котором можно очень много чего увидеть. 

Стек вызовов

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

MainThread - это основной поток. Не обращайте на это внимания, если вы не пишете многопоточную программу. 

Следующие 2 строчки интереснее. Там указаны названия функций и номера строк в файле. Вызовы идут снизу вверх. В нашем случае. 

<module>, example1.py:10 прервался и вызвал функцию и теперь мы находимся  sum_positive, example1.py:2. 

<module> - так указывается если код находится не внутри функции. А если находится внутри функции, мы увидим название функции sum_positive. 

Самая верхняя строчка - это всегда где сейчас находится код. Т.е. example1.py:2 - вторая строчка файла example1.py

Переменные

Следующее окно это список переменных, доступных с текущей строчки кода. Мы сразу видим тип переменной и его значение. Например что у нас тип list и что у нас 5 значений. Все переменные, которые состоят из вложенных значений, можно раскрыть и посмотреть детально:

Мы тут видим индексы каждого элементам списка в переменной values

Кнопки управления

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

Самые важные кнопки это следующие три кнопки:

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

 

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

 

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

Остальные кнопки разберем позже. 

 

Отладка кода (Debugging)

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

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

Мы видим что переменная result пока имеет значение 0. В этой переменной мы будем суммировать все положительные числа. Т.е. ее значение должно расти с каждым следующим положительным числом. 

Нажмите на кнопку Step Over еще 2 раза не спеша, чтобы оказаться на этой строчке снова. 

Так как у нас цикл, выполнение кода будет повторяться пока цикл не закончится. 

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

После выполнения этих строк, вы видим что значение переменной result изменилось. Ему прибавилось значение 1. Пока все идет правильно. Мы сложили первое положительное число. 

Сделав еще один шаг мы увидим что теперь переменная value имеет значение 2, т.е. второй элемент нашего списка values.  Идем дальше и снова проходим через 5 строку кода, попадаем на 3 строку. Мы должны были прибавить к переменной result значение переменной value, т.е. 2 и в итоге получить 3. Но, мы получили 2! surprise

Мы теперь знаем где ошибка! Ошибка в 5 строчке! Что-то там суммируется не так. 

Внимательно посмотрев на код, вы можете заметить что мы перевернули оператор прибавления и вместо += написали =+ . Т.е. вместо прибавления мы просто меняли значение переменной на новую. Потому что выражение result =+ value равно выражению result = value. Плюс стоящий впереди любого значения не имеет никакого значения. 

Думаю многие из вас в самом начале заметили это. Но все могут допустить такую ошибку. Поэтому нам нужен дебаггер. 

Нажмите кнопку Stop. Исправьте код и снова запустите программу в обычном режиме. Теперь мы получим правильный результат выполнения программы: 6. 

 

Автоматическая остановка выполнения в строке с ошибкой

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

Давайте для примера возьмем код, который падает с ошибкой. 

def get_fullname_from_email(email: str) -> tuple[str, str]:
    name, domain = email.split("@")
    firstname, lastname = name.split(".")
    return firstname, lastname


def get_fullnames(emails) -> list:
    fullnames = []
    for email in emails:
        fullname = get_fullname_from_email(email)
        fullnames.append(fullname)

    return fullnames

emails = [
    "bill.gates@microsoft.com", "elon.musk@tesla.net", "peter.petrelli@heroes.com", "steve.jobs@apple.com",
    "tomas.edison@science.com", "salma_hayek@gmail.com", "steve.wozniak@apple2.com", "taylor.swift@singer.com",
]

fullnames = get_fullnames(emails)
print(fullnames)

Этот скрипт должен из каждого емейла в списке вытащить имена и фамилии людей. Учитывая что каждый емейл содержит имя и фамилию. 

Запустим программу в обычном режиме и увидим что программа падает с ошибкой. 

Давайте поставим брейкпоинты на строках 8 и 20. И запустим в режиме дебага. Наша программа остановится на строчке 20 и мы увидим окно дебаггера. 

Нажав на кнопку View Breakpoints вы можете увидеть все брейкпоинты в вашей программе, в каждом файле. А также другие точки останова. 

 

Кроме наших поставленных брейкпоинтов, мы еще видим что по умолчанию включена остановка на исключительных ситуациях - Python Exception Breakpoint. Если у вас не включена, то включите.

Закройте окно, уберите брейкпоинты на строках 8 и 20. Мы убедились что PyCharm сам остановит выполнение на ошибке. И запустим программу снова в режиме дебага. 

Выполнение остановится на 3 строке. И мы увидим следующее:

Это значит что при выполнении 3 строки именно в данный момент времени, т.е. с такими переменными, у нас происходит Exception. 

Мы также видим какая это ошибка, можем посмотреть его детали в переменной __exception__.  Ошибка ValueError говорит что недостаточно значение для распаковки, т.е. мы должны были получить два значения для двух переменных, но поличили меньше в результате name.split(".") . Функция split() должна поделит строчку по указанному символу. 

Давайте посмтрим переменную name в данном случае. Она равна salma_hayek - в ней нет точки, это значит при разделении по точке мы получим только одно значение. Вот почему выходит ошибка. Некоторые имена разделены не точкой, а знаком подчеркивания.

Просмотр выражений 

В таких случаях, вы можете посмотреть что дает то или иное выражение или функция. Для этого нам нужна третье окно дебаггера. Окно называется Watches. Нажмите там кнопку + и введите выражение name.split(".") чтобы увидеть какой результат оно даст.  

Вы можете использовать это окно не влияя на выполнение вашей программы. 

Мы теперь видим что это выражение возвращает список только с одним значением. Поэтому мы не можем его распаковать в две переменные. 

Теперь вы можете остановить дебаггер,  исправить программу и снова его запустить.

 

 

Вот на этом все, это все что нужно знать для отладки Python приложений с помощью PyCharm. Хватит использовать print() для отладки. wink

 

Удачного отлова багов!