Функции листинга с флагом отладки, установленным в R
Я пытаюсь найти глобальный аналог isdebugged()
в R. Мой сценарий заключается в том, что у меня есть функции, которые вызывают вызовы для других функций, все из которых я написал, и я включаю и выключаю debug()
для различных функций во время моей отладки. Однако я могу потерять информацию о том, какие функции установлены для отладки. Когда я забываю и начинаю цикл, я могу получить намного больше результатов (неприятность, но не страшная), или я не могу получить результат, когда кто-то желателен (плохой).
Мой текущий подход заключается в использовании функции, аналогичной приведенной ниже, и я могу вызвать ее с помощью listDebugged(ls())
или перечислить элементы в загруженной библиотеке (примеры ниже). Этого может быть достаточно, но для этого требуется, чтобы я вызывал его со списком каждой функции в рабочей области или в загружаемых пакетах. Я могу обернуть другую функцию, которая их получит. Похоже, что должен быть более простой способ просто "спросить" функцию отладки или запросить некоторую неясную часть среды, в которой он запустил список функций с установленным флагом отладки.
Итак, вопрос из двух частей:
- Существует ли более простой вызов для запроса функций с установленным флагом отладки?
- Если нет, то есть ли какая-то хитрость, которую я забыл? Например, если функция в одном пакете маскирует другую, я подозреваю, что могу вернуть неверный результат.
Я понимаю, что есть еще один метод, который я мог бы попробовать, и это обернуть debug
и undebug
в функции, которые также поддерживают скрытый список отлаженных имен функций. Я еще не убежден, что это безопасно.
UPDATE (8/5/11): Я искал SO и не нашел более ранних вопросов. Однако список SO "связанных вопросов" показал, что более ранний вопрос, похожий, хотя функция ответа на этот вопрос является более подробной и медленной, чем функция предложенный @cbeleites. Более старый вопрос также не содержит никакого кода, хотя я и делал.:)
Код:
listDebugged <- function(items){
isFunction <- vector(length = length(items))
isDebugged <- vector(length = length(items))
for(ix in seq_along(items)){
isFunction[ix] <- is.function(eval(parse(text = items[ix])))
}
for(ix in which(isFunction == 1)){
isDebugged[ix] <- isdebugged(eval(parse(text = items[ix])))
}
names(isDebugged) <- items
return(isDebugged)
}
# Example usage
listDebugged(ls())
library(MASS)
debug(write.matrix)
listDebugged(ls("package:MASS"))
Ответы
Ответ 1
Здесь мой бросок в listDebugged функции:
ls.deb <- function(items = search ()){
.ls.deb <- function (i){
f <- ls (i)
f <- mget (f, as.environment (i), mode = "function",
## return a function that is not debugged
ifnotfound = list (function (x) function () NULL)
)
if (length (f) == 0)
return (NULL)
f <- f [sapply (f, isdebugged)]
f <- names (f)
## now check whether the debugged function is masked by a not debugged one
masked <- !sapply (f, function (f) isdebugged (get (f)))
## generate pretty output format:
## "package::function" and "(package::function)" for masked debugged functions
if (length (f) > 0) {
if (grepl ('^package:', i)) {
i <- gsub ('^package:', '', i)
f <- paste (i, f, sep = "::")
}
f [masked] <- paste ("(", f [masked], ")", sep = "")
f
} else {
NULL
}
}
functions <- lapply (items, .ls.deb)
unlist (functions)
}
- Я выбрал другое имя, так как выходной формат - это только отлаженные функции (в противном случае я легко получаю тысячи функций)
- вывод имеет форму
package::function
(или, скорее, namespace::function
, но пакеты будут иметь пространства имен в ближайшее время).
- Если отлаженная функция маскируется, вывод
"(package::function)"
- по умолчанию просматривается весь путь поиска
Ответ 2
С оригинального вопроса я все больше и больше смотрю Mark Bravington debug
package. Если этот пакет используется, то check.for.traces()
- это соответствующая команда для перечисления тех функций, которые отлаживаются с помощью mtrace
.
Отладочный пакет стоит посмотреть, если вы проводите много времени с отладчиком R и различными параметрами trace
.
Ответ 3
Это простой однострочный с помощью lsf.str
:
which(sapply(lsf.str(), isdebugged))
Вы можете изменить среды внутри функции, см. ?lsf.str
для получения дополнительных аргументов.
Ответ 4
@cbeleites Мне нравится ваш ответ, но это не сработало для меня. Я получил это, чтобы работать, но он менее функциональен, чем ваш (нет рекурсивных проверок, нет красивой печати).
require(plyr)
debug.ls <- function(items = search()){
.debug.ls <- function(package){
f <- ls(package)
active <- f[which(aaply(f, 1, function(x){
tryCatch(isdebugged(x), error = function(e){FALSE}, finally=FALSE)
}))]
if(length(active)==0){
return(NULL)
}
active
}
functions <- lapply (items, .debug.ls)
unlist (functions)
}
Ответ 5
Я постоянно попадаю в оконный фрейм browser
из-за того, что не удается отключить функции. Поэтому я создал две функции и добавил их в свой .Rprofile
. Вспомогательные функции довольно прямолинейны.
require(logging)
# Returns a vector of functions on which the debug flag is set
debuggedFuns <- function() {
envs <- search()
debug_vars <- sapply(envs, function(each_env) {
funs <- names(Filter(is.function, sapply(ls(each_env), get, each_env)))
debug_funs <- Filter(isdebugged, funs)
debug_funs
})
return(as.vector(unlist(debug_vars)))
}
# Removes the debug flag from all the functions returned by `debuggedFuns`
unDebugAll <- function(verbose = TRUE) {
toUnDebug <- debuggedFuns()
if (length(toUnDebug) == 0) {
if (verbose) loginfo('no Functions to `undebug`')
return(invisible())
} else {
if (verbose) loginfo('undebugging [%s]', paste0(toUnDebug, collapse = ', '))
for (each_fn in toUnDebug) {
undebug(each_fn)
}
return(invisible())
}
}
Я проверил их, и он работает очень хорошо. Надеюсь, это поможет!