考虑我们已经为几个函数调用了debug()
来为它们创建一个断点。当我们找到并解决错误时,无论如何undebug()
已经由debug()
通过一个命令标记了所有函数?
这是一个很好的基准,看看你提出的方法是否真的完美:
> library(limma) # bioconductor
> debug(read.ilmn)
> read.ilmn("a.txt") # No problem if this file does not exist
Browse[2]> debug(.read.oneilmnfile) # This is the debug browser for read.ilmn()
Browse[2]> Q # To exit debug browser
> undebug.all() # Here run your proposed function to undebug everything!
> read.ilmn("a.txt")
# Now if the debug browser is not started, you are lucky to pass this test!
您可能会在下面看到接受的答案。任何情况下这个答案都不起作用,或者更干净的版本是非常受欢迎的。
答案 0 :(得分:15)
不,undebug()
所有功能都没有完全可靠的方法。 (我只是这样说,因为我看过它在R-devel和R-help上多次讨论过。)
In this discussion,Brian Ripley称重,注意到:
调试是函数对象的属性(sxpinfo中的一个位),因此您必须遍历所有可到达的对象(如gc所做的那样)才能找到它们。
Here's a snippet罗伯特·绅士回答(负面的)a question关于“是否有一种方便的方法可以随时了解标有debug()
或{{的函数1}}在R会话中“:
你可能没有得到答案,因为答案是否定的 没有简单的方法。
答案 1 :(得分:15)
这是我的解决方案......
编辑:已修订以处理在命名空间中查找对象的问题。代码已经变得有点狡猾,因为我并不真正理解操作/查询命名空间的方法,因为我正在通过反复试验来工作。更清洁的版本将是受欢迎的。几乎可以肯定其他角落案例也会失败。
## return the names of the objects (from a vector of list of
## names of objects) that are functions and have debug flag set
isdebugged_safe <- function(x,ns=NULL) {
g <- if (is.null(ns)) get(x) else getFromNamespace(x,ns)
is.function(g) && isdebugged(g)
}
which_debugged <- function(objnames,ns=NULL) {
if (!length(objnames)) return(character(0))
objnames[sapply(objnames,isdebugged_safe,ns=ns)]
}
all_debugged <- function(where=search(), show_empty=FALSE) {
ss <- setNames(lapply(where,function(x) {
which_debugged(ls(x,all.names=TRUE))
}),gsub("package:","",where))
## find attached namespaces
## (is there a better way to test whether a
## namespace exists with a given name??)
ns <- unlist(sapply(gsub("package:","",where),
function(x) {
if (inherits({n <- try(getNamespace(x),silent=TRUE)},
"try-error")) NULL else x
}))
ss_ns <- setNames(lapply(ns,function(x) {
objects <- ls(getNamespace(x),all.names=TRUE)
which_debugged(objects,ns=x)
}),ns)
if (!show_empty) {
ss <- ss[sapply(ss,length)>0]
ss_ns <- ss_ns[sapply(ss_ns,length)>0]
}
## drop overlaps
for (i in names(ss))
ss_ns[[i]] <- setdiff(ss_ns[[i]],ss[[i]])
list(env=ss,ns=ss_ns)
}
undebug_all <- function(where=search()) {
aa <- all_debugged(where)
lapply(aa$env,undebug)
## now debug namespaces
invisible(mapply(function(ns,fun) {
undebug(getFromNamespace(fun,ns))
},names(aa$ns),aa$ns))
}
该代码也发布在http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R
示例:
library(nlme)
debug(lme)
## define functions
source(url("http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R"))
undebug_all()
fm1 <- lme(distance ~ age, data = Orthodont) # from ?lme
在这种情况下lme
在没有进入调试器的情况下运行。
另一个更难的例子:
library(limma)
source(url("http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R"))
debug(read.ilmn)
debug(limma:::.read.oneilmnfile)
all_debugged()
undebug_all()
read.ilmn()
read.ilmn("a.txt")
注意 read.ilmn()
和read.ilmn("a.txt")
似乎与调试的立场不同(我不明白为什么......)
答案 2 :(得分:8)
这是一个选项,假设您正在调试的函数位于工作空间或全局环境中。可以指定任何特定的环境,使其具有适应性,但这不会适用于所有加载包中的任何功能。
首先通过全球环境中的几个函数来说明:
> bar <- function() {}
> foo <- function() {}
使用lsf.str()
返回工作区中的函数(稍后我们使用unclass()
并将其转换为列表):
> funlist <- as.list(unclass(lsf.str()))
> funlist
[[1]]
[1] "bar"
[[2]]
[1] "foo"
接下来,为这些函数生成一个指标,以确定它们是否已被调试:
> debugged <- sapply(funlist, isdebugged)
> debugged
[1] FALSE FALSE
好的,所以debug()
其中一个功能并重新运行:
> debug(bar)
>
> debugged <- sapply(funlist, isdebugged)
> debugged
[1] TRUE FALSE
最后sapply()
超过funlist
调试的undebug()
函数应用> sapply(funlist[debugged], undebug)
[[1]]
NULL
:
undebugFuns <- function() {
funs <- unclass(lsf.str())
dbg <- sapply(funs, isdebugged)
if(isTRUE(any(dbg))) {
writeLines(paste("Un-debugging:", funs[dbg]))
sapply(funs[dbg], undebug)
} else {
writeLines(paste("Nothing to debug"))
}
invisible()
}
> debug(bar)
> undebugFuns()
Un-debugging: bar
这当然可以封装成一个函数
isdebugged()
debugonce()
未启动的一种调试是通过> debug(bar)
> isdebugged(bar)
[1] TRUE
> undebugFuns()
Un-debugging: bar
> debugonce(bar)
> isdebugged(bar)
[1] FALSE
制定的:
{{1}}
这又是让Josh再次回答他的答案。