Умение правильно использовать точки останова — одна из основных частей отладки. В этой статье я расскажу, как отлаживать и использовать точки останова. Ниже приведен код 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 строками кода и несколькими классами, функциями и файлами это будет не так просто, но выполнение этих шагов отладки поможет приблизиться к поиску ошибок в коде.