有哪些方法可以在R中编辑一个函数?

58

假设我们有以下函数:

foo <- function(x)
{
    line1 <- x
    line2 <- 0
    line3 <- line1 + line2
    return(line3)
}

而我们希望将第二行更改为:

    line2 <- 2

你会如何做到这一点?

一种方法是使用

fix(foo)

并更改该函数。

另一种方法是重新编写该函数。

还有其他方法吗?(请记住,任务是只更改第二行)

我想要的是使用字符串(字符)向量表示函数,然后更改其中一个值,再将其转换回函数。


1
这不是通过将参数传递给函数就能完成的吗?请注意,您还可以将函数作为参数传递。 - Leo Alekseyev
2
嗨Leo - 这个问题是关于当我想要更改别人编写的函数时,但在代码内部不必复制整个函数。 - Tal Galili
如果您需要编辑“内部”函数,我发现以下建议和片段非常有用:nabble: how-to-override-replace-a-function-in-a-package-namespace - stats-hb
Nabble.com已经不存在了。 - IRTFM
5个回答

46

有一个 body<- 函数,它允许您分配函数的新内容。

body(foo)[[3]] <- substitute(line2 <- 2)
foo
#-----------    
function (x) 
{
    line1 <- x
    line2 <- 2
    line3 <- line1 + line2
    return(line3)
}

(“{” 是 body(foo)[[1]],每一行都是列表的一个连续元素。因此第二行是表达式列表中的第三个元素。插入的元素需要是未求值的表达式而不是文本。)

还有一个相应的 formals<- 函数,让人们可以对参数pairlist进行类似的操作。

注意: 如果函数将调用已加载软件包中的附加功能资源,则使用 fixInNamespace 可能比 fix 更好。在控制台中使用时,fix 会将结果分配给 .GlobalEnv


12
最近我被迫做一件类似的事情,但有一个可以改进的地方:你可以深入到列表中更多层级,因此对于问题情况body(foo)[[3]][[3]] <- 2是可行的,不需要使用 substitute - Marek
谢谢。我认为替代是必要的,以保持表达式作为语言项的模式。 - IRTFM
4
如果你要替换整行,那么是需要的。一般来说,类应该匹配:我的方法可以工作,因为我逐个替换数字。如果我想将line2替换为myVariable,则需要使用as.symbol转换。 - Marek
1
昨天我想到了这种方法,当时是在回答一个有关如何构建矩生成函数的问题。它只需要使用替换符号对 *exp(x*t) 进行符号“追加”,其中参数作为 quote() 调用对象传递即可。 - IRTFM

29

或者看一下调试函数trace()。它可能不完全是你需要的,但它可以让你在变更时进行测试,并具有一个很好的功能,即可以通过untrace()返回到原始函数。

trace()base包的一部分,并带有一个良好而详尽的帮助页面。

首先调用as.list(body(foo))查看代码的所有行。

as.list(body(foo))
[[1]]
`{`

[[2]]
line1 <- x

[[3]]
line2 <- 0

[[4]]
line3 <- line1 + line2

[[5]]
return(line3)

然后,您只需通过在trace()中定义参数来定义要添加到函数中的内容以及放置的位置。

trace (foo, quote(line2 <- 2), at=4)
foo (2)
[1] 4

一开始我说trace()可能不是你想要的,因为你并没有真正改变第三行代码,而是在下面插入了一行代码来重新分配对象line2的值。如果你打印出现在跟踪的函数的代码,情况就会更清晰。

body (foo)
{
    line1 <- x
    line2 <- 0
    {
        .doTrace(line2 <- 2, "step 4")
        line3 <- line1 + line2
    }
    return(line3)
}

24

fix 是我所知道的最好的方法来解决这个问题,虽然您也可以使用 edit 并重新分配它:

fix 是我知道的最佳方案,不过你也可以使用 edit 然后重新赋值:

foo <- edit(foo)

fix在内部的操作是这样的。如果你想要将你的更改重新分配给不同的名称,那么你可能想要这样做。


17

fixInNamespace 类似于 fix 方法,针对包中的函数(包括未导出的函数)。


我认为这可能是最好的答案。当我试图从包中破解函数时,我经常需要使用environment(new) <- environment(old)跟踪新破解函数的创建。这可以防止在控制台关联环境中无法找到不在搜索树上的辅助函数。 - IRTFM

9
您可以使用“body”函数。该函数将返回函数的主体:
fnx = function(a, b) { return(a^2 + 7*a + 9)}
body(fnx)
# returns the body of the function

所以一种良好的编辑函数的方法是使用赋值语句左侧的“body”:

body(fnx) = expression({a^2 + 11*a + 4})

1
这实际上是使用 body<- 函数的一个例子。 - IRTFM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接