什么是在函数中给定行设置调试代码的快速方法? [英] What is a fast way to set debugging code at a given line in a function?
问题描述
序言:
R的 trace()
是一个功能强大的调试工具,允许用户插入调试代码在任何功能的选定的地方。不幸的是,从命令行使用它可能相当费力。
作为一个人为的例子,我们想要插入调试代码,将报告间隔间隔由 pretty.default()
计算。我想在 delta
的值之后立即插入代码,大约从函数定义的底部开始大约四行。 (键入 pretty.default
以查看我的意思。)
要指示该行,我需要找到它对应的代码中的哪一步。答案证明是步骤列表(c(12,3,3))
,通过执行以下步骤,我将零开始:
as.list(body(pretty.default))
as.list(as.list(body(pretty.default))[[ 12]])
as.list(as.list(as.list(body(pretty.default))[[12]])[[3]])
as.list(as.list (as.list(body(pretty.default))[[12]])[[3]])[[3]]
然后我可以插入这样的调试代码:
trace(what ='pretty.default' ,
tracer = quote(cat(\ the delta of delta is:,delta,\\\
\\\
)),
at = list(c(12,3,3 ))
##尝试
a < - pretty(c(1,7843))
b< - pretty(c(2,23))
##清除
untrace('pretty.default')
问题:
所以这里是我的问题:有没有办法打印一个函数(或其解析的版本),它们所属的步骤很好地贴上标签的行? (根据Venables和Ripley,S-plus有一个函数 tprint()
,生成一个函数的正文列表,用于在
参数,但R似乎没有等价物。)另外,还有另一种更简单的方法,从命令行到快速设置功能中特定行的调试代码?跟踪
的
附录:
我使用 pretty.default()
示例,因为它是相当温驯,但使用真实/有趣的功能,重复使用 as.list()
变得厌烦和分心。这是一个例子:
as.list(as.list(as.list(as.list(as.list列表(as.list(as.list(body(#
model.frame.default))[[26]])[[3]])[[2]])[[4] ])[[3]])[[4]])[[4]])[[4]])[[3]]
这是一个方便的包装器,用于检测该片段:
library(codetools)
ff< - function(f,tar){
cc < - function(e,w){
if(length(w $ pos) > 0&&
grepl(w $ tar,paste(deparse(e),collapse =\\\
),fixed = TRUE)){
cat(rev(w $ pos ),:,deparse(e),\\\
)
w $ ret $ vals< - c(w $ ret $ vals,list(rev(w $ pos)))
对于(ee in.list(e)){
if(!missing(ee)){$ b $($)
w $ pos< - c(0,w $ pos) bw $ pos [1]< - w $ pos [1] + 1
walkCode(ee,w)
}
}
}
$ b $ < - list(pos = c(),
tar = tar,
ret = new.env(),
handler = function(v,w)NULL,
call = cc,
leaf = function(e,w)NULL)
walkCode(body(f),w = w )
w $ ret $ vals
}
然后,
> r< - ff(pretty.default,delta< - diff(range(z $ l,z $ u))/ z $ n)
12:if(!eps.correct& z $ n){delta <-diff(range(z $ l,z $ u))/ z $ n if(any(small <-abs(s)< 1e-14 * delta) ]< - 0}
12 3:{delta< - diff(range(z $ l,z $ u))/ z $ n if(any(small <-abs(s)<1e -14 * delta))s [small] < - 0}
12 3 2:delta< - diff(range(z $ l,z $ u))/ z $ n
> r
[[1]]
[1] 12
[[2]]
[1] 12 3
[ 3]]
[1] 12 3 2
> r< - ff(model.frame.default,)stop(gettextf(\factor%s具有新的级别%s\,nm,paste(nxl [m],)
26 3 2 4 3 4 4 4 3:stop(gettextf(factor%s具有新的级别%s,nm,paste(nxl [m],collapse =,)),域= NA)
> r
[[1]]
[1] 26 3 2 4 3 4 4 4 3
,您可以通过内容定义跟踪器:
traceby< - function(fun,tar,cer){
pre>
untrace(deparse(substitute(fun)))
r< - ff(fun,tar)
r< - r [which.max sapply(r,length))]
trace(what = deparse(substitute(fun)),tracer = cer,at = r)
}
然后,
> traceby(pretty.default, ((\\,delta,delta,( $)$)$)
在包base中撤消函数pretty.default
12 3 3:if(any(small < - abs(s)< 1e- 14 * del ta))s [small]< - 0
包base中的跟踪功能pretty.default
[1]pretty.default
> a< - pretty(c(1,7843))
跟踪pretty.default(c(1,7843))步骤12,3,3
delta的值为:2000
> (c(2,23))
跟踪pretty.default(c(2,23))步骤12,3,3
delta的值为:5
Preamble:
R's
trace()
is a powerful debugging tool, allowing users to "insert debugging code at chosen places in any function". Unfortunately, using it from the command-line can be fairly laborious.As an artificial example, let's say I want to insert debugging code that will report the between-tick interval calculated by
pretty.default()
. I'd like to insert the code immediately after the value ofdelta
is calculated, about four lines up from the bottom of the function definition. (Typepretty.default
to see where I mean.) To indicate that line, I need to find which step in the code it corresponds to. The answer turns out to be steplist(c(12, 3, 3))
, which I zero in on by running through the following steps:as.list(body(pretty.default)) as.list(as.list(body(pretty.default))[[12]]) as.list(as.list(as.list(body(pretty.default))[[12]])[[3]]) as.list(as.list(as.list(body(pretty.default))[[12]])[[3]])[[3]]
I can then insert debugging code like this:
trace(what = 'pretty.default', tracer = quote(cat("\nThe value of delta is: ", delta, "\n\n")), at = list(c(12,3,3))) ## Try it a <- pretty(c(1, 7843)) b <- pretty(c(2, 23)) ## Clean up untrace('pretty.default')
Questions:
So here are my questions: Is there a way to print out a function (or a parsed version of it) with the lines nicely labeled by the steps to which they belong? (According to Venables and Ripley, S-plus has a function
tprint()
that "produces a numbered listing of the body of a function for use with theat
argument oftrace
", but R seems to have no equivalent.) Alternatively, is there another easier way, from the command line, to quickly set debugging code for a specific line within a function?Addendum:
I used the
pretty.default()
example because it is reasonably tame, but with real/interesting functions, repeatedly usingas.list()
quickly gets tiresome and distracting. Here's an example:as.list(as.list(as.list(as.list(as.list(as.list(as.list(as.list(as.list(body(# model.frame.default))[[26]])[[3]])[[2]])[[4]])[[3]])[[4]])[[4]])[[4]])[[3]]
解决方案Here is a convenient wrapper for detecting the piece:
library(codetools) ff <- function(f, tar) { cc <- function(e, w) { if(length(w$pos) > 0 && grepl(w$tar, paste(deparse(e), collapse = "\n"), fixed = TRUE)) { cat(rev(w$pos), ": ", deparse(e), "\n") w$ret$vals <- c(w$ret$vals, list(rev(w$pos))) } w$pos <- c(0, w$pos) for (ee in as.list(e)){ if (!missing(ee)) { w$pos[1] <- w$pos[1] + 1 walkCode(ee, w) } } } w <- list(pos = c(), tar = tar, ret = new.env(), handler = function(v, w) NULL, call = cc, leaf = function(e, w) NULL) walkCode(body(f), w = w) w$ret$vals }
and then,
> r <- ff(pretty.default, "delta <- diff(range(z$l, z$u))/z$n") 12 : if (!eps.correct && z$n) { delta <- diff(range(z$l, z$u))/z$n if (any(small <- abs(s) < 1e-14 * delta)) s[small] <- 0 } 12 3 : { delta <- diff(range(z$l, z$u))/z$n if (any(small <- abs(s) < 1e-14 * delta)) s[small] <- 0 } 12 3 2 : delta <- diff(range(z$l, z$u))/z$n > r [[1]] [1] 12 [[2]] [1] 12 3 [[3]] [1] 12 3 2 > r <- ff(model.frame.default, "stop(gettextf(\"factor '%s' has new level(s) %s\", nm, paste(nxl[m],") 26 3 2 4 3 4 4 4 3 : stop(gettextf("factor '%s' has new level(s) %s", nm, paste(nxl[m], collapse = ", ")), domain = NA) > r [[1]] [1] 26 3 2 4 3 4 4 4 3
and you can define the tracer by contents:
traceby <- function(fun, tar, cer) { untrace(deparse(substitute(fun))) r <- ff(fun, tar) r <- r[which.max(sapply(r, length))] trace(what = deparse(substitute(fun)), tracer = cer, at = r) }
then,
> traceby(pretty.default, "if (any(small <- abs(s) < 1e-14 * delta)) s[small] <- 0", quote(cat("\nThe value of delta is: ", delta, "\n\n"))) Untracing function "pretty.default" in package "base" 12 3 3 : if (any(small <- abs(s) < 1e-14 * delta)) s[small] <- 0 Tracing function "pretty.default" in package "base" [1] "pretty.default" > a <- pretty(c(1, 7843)) Tracing pretty.default(c(1, 7843)) step 12,3,3 The value of delta is: 2000 > b <- pretty(c(2, 23)) Tracing pretty.default(c(2, 23)) step 12,3,3 The value of delta is: 5
这篇关于什么是在函数中给定行设置调试代码的快速方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!