Рекомендации для “Динамической/интерактивной” отладки функций в R?

При отладке функции я обычно использую

library(debug)
mtrace(FunctionName)
FunctionName(...)

И это работает вполне хорошо на меня.

Однако иногда я пытаюсь отладить комплексную функцию, которую я не знаю. В этом случае я могу найти, что в той функции существует другая функция, в которую я хотел бы "войти" ("отладка") - так, чтобы лучше понять, как весь процесс работает.

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

library(debug)
mtrace(FunctionName)
FunctionName(...)
# when finding a function I want to debug inside the function, run again:
mtrace(FunctionName.SubFunction)

Вопрос - там лучший/более умный способ сделать интерактивную отладку (как я описал), что я мог бы отсутствовать?

p.s: Я знаю что там где различные вопросы, которые задают на предмете на ТАК (см. здесь). Все же я не смог столкнуться с подобным вопросом/решением тому, что я спросил здесь.

6
задан Community 23 May 2017 в 11:55
поделиться

3 ответа

Не совсем уверен в целесообразности использования, но когда вы столкнетесь с проблемой, вы можете вызвать функцию traceback(). Это покажет путь вызова вашей функции по стеку, пока она не столкнулась с проблемой. Если вы хотите работать сверху вниз, вы можете вызвать функцию debug для каждой из функций, приведенных в списке, перед вызовом вашей функции. Тогда вы пройдете весь процесс с самого начала.

Вот пример того, как вы могли бы сделать это более систематическим образом, создав функцию для прохождения всего процесса:

walk.through <- function() {
  tb <- unlist(.Traceback)
  if(is.null(tb)) stop("no traceback to use for debugging")
  assign("debug.fun.list", matrix(unlist(strsplit(tb, "\\(")), nrow=2)[1,], envir=.GlobalEnv)
  lapply(debug.fun.list, function(x) debug(get(x)))
  print(paste("Now debugging functions:", paste(debug.fun.list, collapse=",")))
}

unwalk.through <- function() {
  lapply(debug.fun.list, function(x) undebug(get(as.character(x))))
  print(paste("Now undebugging functions:", paste(debug.fun.list, collapse=",")))
  rm(list="debug.fun.list", envir=.GlobalEnv)
}

Вот фиктивный пример ее использования:

foo <- function(x) { print(1); bar(2) }
bar <- function(x) { x + a.variable.which.does.not.exist }
foo(2)

# now step through the functions
walk.through() 
foo(2)

# undebug those functions again...
unwalk.through()
foo(2)

IMO, это не кажется наиболее разумным. Более разумно просто войти в функцию, где возникает проблема (т.е. на самом низком уровне), и проделать обратный путь.

Я уже описывал логику этой базовой процедуры в "любимом приеме отладчика".

5
ответ дан 8 December 2019 в 18:32
поделиться

Мне нравится options(error=recover), как подробно описано ранее на SO. Тогда все останавливается в точке ошибки и можно проверить.

5
ответ дан 8 December 2019 в 18:32
поделиться

(я являюсь автором пакета 'debug', в котором находится 'mtrace')

Если определение 'SubFunction' находится вне 'MyFunction', тогда вы можете просто mtrace ' SubFunction »и не нужно отслеживать« MyFunction ». К тому же функции работают быстрее, если они не являются "mtrace'd", так что mtrace можно выполнять ровно настолько, насколько это необходимо. (Но вы, вероятно, уже знаете эти вещи!)

Если MyFunction определена только внутри SubFunction, один прием, который может помочь, - это использование условной точки останова в MyFunction. Вам нужно будет «mtrace (MyFunction)», затем запустить его, и, когда появится окно отладки, узнать, в какой строке определена «MyFunction». Скажите, что это строка 17.Тогда должно работать следующее:

D (n)> bp (1, F) # не пытайтесь снова показывать окно для MyFunction D (n)> bp (18, {mtrace (SubFunction); FALSE}) D (n)> go ()

Должно быть ясно, что он делает (или будет, если вы попробуете).

Единственными недостатками являются: необходимость делать это снова всякий раз, когда вы меняете код MyFunction, и; замедление, которое может произойти из-за трассировки самой MyFunction.

Вы также можете поэкспериментировать с добавлением аргумента «debug.sub» к «MyFunction», который по умолчанию имеет значение FALSE. В коде «MyFunction» добавьте эту строку сразу после определения «SubFunction»:

if (debug.sub) mtrace (SubFunction)

Это позволяет избежать необходимости отслеживать саму «MyFunction», но делает требуют, чтобы вы могли изменить его код.

3
ответ дан 8 December 2019 в 18:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: