Python: Отладка
Даже у самых опытных разработчиков код редко работает идеально с первого раза. Чем опытнее разработчик, тем увереннее он отлаживает его, то есть анализирует ошибки и устраняет их.
Навык отладки сам по себе не появится. Его нужно развивать, причем как можно раньше. По ходу обучения вы будете выполнять задания и практиковаться, и со временем анализ ошибок войдет в привычку.
Как найти ошибку в коде
Отладка методом тыка занимает много времени. Гораздо продуктивнее сначала понять, что именно пошло не так, а потом устранять причину. С понимания начинается любая работа с ошибками.
Первым делом изучите трейсбек (traceback). Трейсбек содержит список всех вызовов функций от старта программы до места с ошибкой. По нему видно, какие функции выполнились успешно, а где возникли проблемы. Каждая запись указывает на файл, строчку и выполняемую функцию.
Представим, что вы написали код в файле users.py и вызвали функцию main() на четвертой строчке. Запись в трейсбеке будет выглядеть так:
File "users.py", line 4, in <module>
main()Здесь видно не только файл и строчку, но и название модуля. По нему можно определить, в вашем ли коде возникла проблема или в сторонней библиотеке.
Когда трейсбек доходит до проблемного места, он выдает сообщение об ошибке. Например:
NameError: name 'create' is not definedСообщение говорит, что название create не определено. Такая ошибка чаще всего означает опечатку в имени. Если английский еще не очень, поможет переводчик.
Вместе трейсбек и сообщение об ошибке выглядят так:
Traceback (most recent call last):
File "users.py", line 4, in <module>
main()
File "users.py", line 2, in main
create()
NameError: name 'create' is not definedВся цепочка событий видна сразу. Программа успешно дошла до main(), потом перешла к create() и здесь столкнулась с ошибкой в названии.
Типы ошибок
Самые понятные ошибки в Python называются синтаксическими. Они возникают, когда код оформлен неверно, например из-за не той кавычки или пропущенной скобки. В выводе всегда присутствует SyntaxError:.
Посмотрим на пример. Здесь синтаксическая ошибка из-за того, что открывающая кавычка " не совпадает с закрывающей ':
Traceback (most recent call last):
File "users.py", line 2
print("Hello" + "world')
^
SyntaxError: EOL while scanning string literalТруднее всего исправлять ошибки программирования. Сюда входят вызов несуществующей функции, использование необъявленной переменной, передача аргументов неверного типа. Обычно они возникают не в том месте, где настоящая причина, что и усложняет диагностику.
Сложнее всего бороться с логическими ошибками. Программа работает без исключений, но выдает неверный результат при некоторых входных данных. Никакого сообщения об ошибке нет, только неожиданный вывод. Например, функция должна считать сумму, но считает разность:
# Функция должна считать сумму чисел, но считает разность:
def sum(a: int, b: int) -> int:
return a - b
# При таком вызове ошибка неочевидна, потому что
# и при сложении, и при вычитании будет один и тот же результат
sum(4, 0) # 4Способы отладки
В основе любого метода отладки лежит наблюдение за переменными в процессе выполнения. Посмотрим на конкретную функцию.
Ниже функция, которая считает сумму чисел от start до finish. При start=3 и finish=5 она должна вычислить 3 + 4 + 5.
def sum_of_series(start: int, finish: int) -> int:
result = 0
n = start
while n < finish:
result = result + n
n = n + 1
return resultВ функции ключевые переменные n и result. Чтобы найти ошибку, нужно посмотреть, какие значения они принимают на каждой итерации.
Для этого существуют визуальные отладчики. Они встраиваются в популярные редакторы кода и позволяют выполнить программу по шагам, наблюдая за переменными в реальном времени. Найти подходящий можно по запросу «Python debuggers» в Google.
На Хекслете вместо отладчика используется отладочная печать. Принцип тот же, только значения переменных выводятся через обычный print. То, что печатается, отображается во вкладке OUTPUT.
def sum_of_series(start: int, finish: int) -> int:
result = 0
n = start
while n < finish:
print("new iteration !!!!")
print(n)
result = result + n
n = n + 1
print(result)
return result
sum_of_series(3, 5)
# new iteration !!!!
# 3
# 3
# new iteration !!!!
# 4
# 7Вывод показывает, что итераций на одну меньше, чем нужно. Пятерка (finish) в сложение не попала. В условии стоит n < finish вместо n <= finish. Нужно заменить знак < на <=.
Начинающие разработчики часто расстраиваются из-за ошибок и считают себя невнимательными. Ошибки есть у всех, и у джунов, и у сеньоров. Разница в том, насколько уверенно ты их находишь.
Начинающие думают, что хороший разработчик смотрит на код и сразу понимает, что не так. Это редко работает на практике. Фрагмент кода без контекста мало что говорит. Если хотите попросить совет у опытного разработчика, первым делом покажите сообщение об ошибке.
Задание
Реализуйте функцию compress(string), которая сжимает строку методом RLE (Run-Length Encoding).
Алгоритм: если символ повторяется несколько раз подряд, он заменяется на символ и количество повторений. Одиночные символы записываются без цифры.
Примеры:
compress("aaabcccc") # "a3bc4"
compress("abcd") # "abcd"
compress("aabbaa") # "a2b2a2"
compress("") # ""Этот алгоритм используется в реальных форматах сжатия данных — например, в старых факс-протоколах и BMP-файлах.
Алгоритм
- Идти по строке, считая количество подряд идущих одинаковых символов
- Как только символ меняется — записать предыдущий символ и счётчик (если больше 1)
- Не забыть обработать последнюю группу после окончания цикла
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
from solution import compress
def test():
assert compress("aaabcccc") == "a3bc4"
assert compress("abcd") == "abcd"
assert compress("aabbaa") == "a2b2a2"
assert compress("a") == "a"
assert compress("") == ""
assert compress("zzz") == "z3"Решение учителя откроется через:
20:00
