Рекомендации по «Динамической / интерактивной» отладке функций в R? - PullRequest
6 голосов
/ 09 июля 2010

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

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: Мне известно, что там, где задавались различные вопросы по теме SO (см. здесь ). И все же я не смог найти похожий вопрос / решение, которое я задал здесь.

Ответы [ 3 ]

5 голосов
/ 09 июля 2010

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

5 голосов
/ 09 июля 2010

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

ИМО, это не самая разумная вещь, которую можно сделать.Имеет больше смысла просто перейти к функции, в которой возникает проблема (т. Е. На самом низком уровне), и работать в обратном направлении.

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

3 голосов
/ 16 июля 2010

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

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

Если «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, но требует от вас возможности изменить его код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...