假设我有一个函数,我想稍微调整一下它的行为(比如跳过某行)
1.复制粘贴函数并更改。
1.使用debug
以交互方式更改代码。
1.使用trace
注入自己的代码。
我只对这篇文章的选项3感兴趣。
例如,让我们假设下面的代码非常简单:
f <- function(dbg) {
x <- rnorm(1)
if (dbg) {
cat("Message 1\n")
}
if (x < 0 & dbg) {
cat("Message 2\n")
}
x
}
如果(不管什么原因)我想跳过Message 2
(但保留Message 1
),我可以使用trace
如下:
set.seed(12231)
untrace(f)
f(TRUE)
# Message 1
# Message 2
# [1] -0.5787277
trace(f, quote(dbg <- FALSE), at = 4, print = FALSE)
set.seed(12231)
f(TRUE)
# Message 1
# [1] -0.5787277
现在假设一个稍微不同的函数g
:
g <- function() {
x <- rnorm(1)
cat("Message\n")
cat("Message 2\n")
x
}
- 从概念上讲 * 我想做的事情是:
trace(g, quote(if(FALSE)), at = 4, print = FALSE)
但这显然行不通。
有没有一种方法可以使用trace
跳过某些行?或者是我唯一的选择来复制,粘贴和编辑函数?
2条答案
按热度按时间fkvaft9z1#
实际上,
trace
所做的(对于常规函数)就是在函数体内的所需位置插入对.doTrace
的调用。我们可以手动执行相同的操作以达到完全相同的效果。但是在你的例子中,我们想要 remove 而不是add;我们也可以这样做:
我尝试将修改后的函数体作为
tracer
传递给trace
,让它在trace
中工作。不幸的是,我无法阻止原始函数在之后执行:向tracer
添加显式的return()
调用没有任何作用(因为.doTrace
使用eval.parent
来计算tracer
代码,而eval
内部的return
不会退出调用范围)。我 * 可以 * 使用stop()
而不是return()
。然而,这是不希望的,因为它总是下降到 * 顶层 * 而不是g
的调用者。我试图通过安装globalCallingHandler
来影响这一点,但没有适当的重启我可以调用,并且无论如何,定期的重新启动会使我们直接回到g
,而不是它的调用者。我不知道这是否可以规避,甚至在原则上:它本质上需要修改活动调用堆栈-重新启动 do,但据我所知只有非常有限的方式(即通过
abort
重新启动删除整个调用堆栈,或通过在最内层调用帧内恢复)。azpvetkf2#
这里有几种方法,都以某种方式依赖于重新定义
cat
。1)将cat重新定义为list像这样重新定义
cat
。如果不需要Tracing
消息,请添加print=FALSE
参数。2)检查cat arg另一种方法是:
3)计算cat调用次数设置i为0,然后每次调用
cat
时更新一次,如果不是第二次才执行。