А вы отлаживаете свой код с помощью print()?
Наверняка ответом на этот вопрос будет - да. Мы все прекрасно знаем, что использование print() для отладки кода далеко от "лучших практик". Тем не менее используем этот приём, не смотря на то, что есть более продвинутые инструменты отладки, такие как browser() и debug(), потому, что он не требует каких то временных затрат.
Ниже пример отладки с print():
other_function <- function(x) x * 5 - 7
more_calculations <- function() NULL
some_advanced_function <- function(x) {
print("Я тут")
y <- other_function(x)
print(y)
more_calculations()
print("Надеюсь дойти сюда!!!!")
}
В лучшем случае такая отладка выдаст следующую информацию в консоль:
some_advanced_function(4)
[1] "Я тут"
[1] 13
[1] "Надеюсь дойти сюда!!!!"
Какие недостатки в print():
● Всё, что он вам выведет в консоль - это значение переменной, или заданный текст, но мы не понимаем какое выражение дало этот результат,
● Также мы не увидим к какой строке кода в файле относится кокнетное сообщение.
Т.к. мы не смотря ни на что используем этот приём, за то, что он не требует от нас дополнительных усилий, то есть смысл найти аналогичный по трудозатратам способ отладки, но при этом немного более функциональный. И такой способ нам предоставляет пакет icecream, который был разработан под вдохновением от одноимённого Python модуля.
Какие преимущества даёт icecream():
● Его основная функция - ic(), что уже само по себе является преимуществом, поскольку набрать ic() быстрее и проще чем print();3
● ic() автоматически печатает выражение вместе со своим значением;
● ic() включает максимально точную информацию о файле и позиции в файле, если вы вызываете его без аргументов
Давайте перепишем приведённый выше пример с помощью ic():
library(icecream)
other_function <- function(x) x * 5 - 7
more_calculations <- function() NULL
some_advanced_function <- function(x) {
ic()
y <- other_function(x)
ic(y)
more_calculations()
ic()
}
some_advanced_function(4)
Что мы изменили:
1. Функцию print() заменили на ic()
2. Вместо вызова print() с бесполезным текстом "HERE" и "I HOPE IT GETS THERE!!!!" мы вызываем ic() без дополнительных аргументов.
Сохраним его в файле external.R и запустим командой source("~/external.R"):
> source("~/33.R")
ℹ️ ic| `some_advanced_function()` in ~/33.R:8:2
ℹ️ ic| `y`: num 13
ℹ️ ic| `some_advanced_function()` in ~/33.R:12:2
Что изменилось в результате работы кода:
1. Теперь в консоли мы видим вместо "HERE" и "I HOPE IT GETS THERE!!!!" подробную информацию о том, в каком файле, на какой строке и какой функцией были выполнены эти вычисления.
2. При печати переменной y, помимо её значения мы видим имя самой переменной, и тип данных, которые она хранит.
Отключаем вывод ic()
Ещё одной проблемой при отладке через print() является то, что нам после процесса отладки необходимо убрать из кода все эти выводы сообщений, если процесс отладки был долгим, то наши принты могут в эмоциональном порыве покрыться нецензурными выражениями, и если вы потом такой код предоставите клиенту, который увидит в это а интерфейсе Shiny приложения или просто в выводе консоли, то может быть неловкая ситуация.
В пакете icecream предусмотрен механизм подавления вывода команды ic(), и возобновления её вывода в консоль.
- ic_disable() - отключает вывод функции ic()
- ic_enable() - возобновляет работу ic()
Какие преимущества мы получили:
1. Пишем меньше кода
2. Получаем больше информации для отладки
3. Можем отключать вывод доп информации в консоль, не удаляя из кода ic()
Ссылки:
- Данный пост является кратким пересказом статьи "Ice Cream for R Programmers"
#заметки_по_R