Умение правильно использовать точки останова — одна из основных частей отладки. В этой статье я расскажу, как отлаживать и использовать точки останова. Ниже приведен код Python, который должен решить следующую проблему:
Фруктовый магазин продает 3 вида фруктов (яблоко, апельсин, банан). Каждый фрукт имеет свою цену за фунт. Мы предполагаем, что каждый фрукт продается в одинаковом количестве каждый день. Сумма за фрукт разная (например, в магазине каждый день продается 10 фунтов яблок, но 20 фунтов апельсинов).
ПРОБЛЕМА: Нам нужно выяснить, является ли годовой объем продаж больше, равен или меньше 50 000 долларов.
1. applePrice = 1 # $1 per pound 2. orangePrice = 2 # $2 per pound 3. bananaPrice = 3 # $3 per pound 4. 5. appleSold = 10 # 10 pounds of apple is sold every day 6. orangeSold = 20 # 20 pounds of orange is sold every day 7. bananaSold = 30 # 30 pounds of banana is sold every day 8. 9. appleDailySales = applePrice * appleSold # expected: $10 10. orangeDailySales = orangePrice * orangeSold # expected: $40 11. bananaDailySales = bananaPrice + bananaSold # expected: $90 12. 13. totalDailySales = appleDailySales + orangeDailySales + bananaDailySales # expected: $140 14. 15. totalYearlySales = 365 * totalDailySales # expected: $51,100 16. 17. if totalYearlySales > 50000: 18. print("greater") 19. elif totalYearlySales == 50000: 20. print("equal") 21. else: 22. print("less")
В ЭТОМ КОДЕ ЕСТЬ ОШИБКА (ОШИБКИ), которые нам нужно найти в этой статье. Вот общий подход, который я бы выбрал. Это может быть не единственный и не лучший способ отладки, просто некоторая общая идея о том, как подходить к отладке и точкам останова.
1) Сначала я запускаю программу и смотрю, какой результат. После запуска программы она печатает «меньше». Чтобы узнать, правильный ли это результат, мне нужно выяснить ОЖИДАЕМЫЙ результат программы. После выполнения вычислений (см. комментарии к фрагменту кода) я вижу, что «totalYearlySales» должно быть 51 100 долларов, и поэтому наша программа должна была напечатать «больше». Теперь, когда я знаю, что ОЖИДАЕМЫЙ результат («больше») отличается от ФАКТИЧЕСКОГО результата («меньше»), я знаю, что в программе что-то не так.
2) Последний оператор печати происходит в последнем блоке кода, поэтому я ставлю точку останова на строку 17:
17. if totalYearlySales > 50000: 18. print("greater") 19. elif totalYearlySales == 50000: 20. print("equal") 21. else: 22. print("less")
чтобы увидеть, что такое «totalYearlySales» в этот момент. Если я сейчас запущу программу в режиме отладки, она остановится на строке 17, и я увижу, что ФАКТИЧЕСКОЕ значение «totalYearlySales» в этот момент равно 30 295, что отличается от нашего
ОЖИДАЕМОГО значения (51 100) . Теперь мы знаем, что что-то пошло не так перед строкой 17.
3) Затем я вижу, что «totalYearlySales» последний раз установлен в следующей строке, поэтому я ставлю еще одну точку останова на строку 15.
15. totalYearlySales = 365 * totalDailySales
После запуска программа останавливается на этой строке, и я проверяю ОЖИДАЕМОЕ и АКТУАЛЬНОЕ значения «totalDailySales». После выполнения вычислений ОЖИДАЕМОЕ значение «totalDailySales» равно 140, однако ФАКТИЧЕСКОЕ значение этой переменной равно 83. Это означает, что перед этой строкой что-то пошло не так.
4) Возвращаясь назад, я вижу, что значение «totalDailySales» в последний раз установлено в следующей строке, поэтому я ставлю еще одну точку останова на строку 13.
13. totalDailySales = appleDailySales + orangeDailySales + bananaDailySales # expected: $140
После запуска программа останавливается на этой строке, и я проверяю ОЖИДАЕМЫЕ и АКТУАЛЬНЫЕ значения следующих переменных: «appleDailySales», «orangeDailySales», «bananaDailySales».
- ОЖИДАЕМОЕ значение «appleDailySales» равно 10 (1x10), и ФАКТИЧЕСКОЕ значение нашей программы также равно 10.
- ОЖИДАЕМОЕ значение «orangeDailySales» равно 40 (2x20), и ФАКТИЧЕСКОЕ значение нашей программы также равно 40.
- ОЖИДАЕМОЕ значение «bananaDailySales» равно 90 (3x30), однако ФАКТИЧЕСКОЕ значение нашей программы равно 33. Существует несоответствие для «bananaDailySales», что означает, что с этой переменной что-то пошло не так.
5) Возвращаясь назад, я вижу, что значение «totalDailySales» в последний раз установлено в следующей строке, поэтому я ставлю еще одну точку останова на строку 11.
11. bananaDailySales = bananaPrice + bananaSold
Присмотревшись к этой строке, я замечаю, что в ней есть логическая ошибка. Вместо того, чтобы умножать цену на количество (*), я их сложил (+), поэтому переменная «bananaDailySales» некорректна.
Вуаля, мы нашли ошибку. Исправим, заменив «+» на «*» и снова запустим всю программу, чтобы посмотреть, сработало ли на этот раз. После запуска программы
мы видим, что она выводит «больше», чего мы и ожидали, поэтому вполне вероятно, что наша программа работает правильно.
6) Возможно, что после исправления этой ошибки и запуска программы мы все равно получим неправильный результат (может быть, цена яблока была введена неправильно, или, может быть, в задаче используется високосный год с 366 днями вместо 365 и т. д.). В этом случае нам нужно будет повторять шаги, упомянутые выше, пока мы не найдем и не исправим все ошибки.
Вывод: на протяжении всего процесса отладки мы использовали основной принцип отладки, заключающийся в сравнении ОЖИДАЕМЫХ и РЕАЛЬНЫХ результатов в разных точках кода. Этот пример кода был довольно простым, и опытные программисты, вероятно, могли бы найти ошибку, просто взглянув на него, не выполняя всех этих сравнений. Однако в более сложном коде с 1000 строками кода и несколькими классами, функциями и файлами это будет не так просто, но выполнение этих шагов отладки поможет приблизиться к поиску ошибок в коде.