什么是在函数中给定行设置调试代码的快速方法? [英] What is a fast way to set debugging code at a given line in a function?

查看:92
本文介绍了什么是在函数中给定行设置调试代码的快速方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

序言:



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){
untrace(deparse(substitute(fun)))
r< - ff(fun,tar)
r< - r [which.max sapply(r,length))]
trace(what = deparse(substitute(fun)),tracer = cer,at = r)
}
pre>

然后,

 > 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 of delta is calculated, about four lines up from the bottom of the function definition. (Type pretty.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 step list(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 the at argument of trace", 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 using as.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆