即使过度分配,也可以检索包函数的原始版本

时间:2013-05-10 01:28:04

标签: r

假设我替换了一个包的函数,例如knitr:::sub_ext。 (注意:我特别感兴趣的是内部函数,即:::只能访问::而不是library(knitr) my.sub_ext <- function (x, ext) { return("I'm in your package stealing your functions D:") } # replace knitr:::sub_ext with my.sub_ext knitr <- asNamespace('knitr') unlockBinding('sub_ext', knitr) assign('sub_ext', my.sub_ext, knitr) lockBinding('sub_ext', knitr) ,但相同的答案可能适用于两者)。

knitr:::sub_ext

问题:有没有办法在我完成此操作后检索原始 sub_ext?最好不要重装包装?


(我知道有些人想知道我为什么要这么做,所以这就是。不需要阅读这个问题)。我一直在修补包中的一些函数(实际上不是original.sub_ext <- knitr:::sub_ext new.sub_ext <- function (x, ext) { # some extra code that does something first, e.g. x <- do.something.with(x) # now call the original knitr:::sub_ext original.sub_ext(x, ext) } # now set knitr:::sub_ext to new.sub_ext like before. 函数...):

original.sub_ext

我同意这通常不是一个好主意(在大多数情况下,这些都是快速修复,直到更改进入CRAN,或者它们是“功能请求”,永远不会被批准,因为它们有些特定于案例)。

上面的问题是,如果我不小心执行了两次(例如,它在我运行两次而不重新启动R的脚本的顶部),第二次new.sub_ext实际上是前一个{{ 1}}而不是 real knitr:::sub_ext,所以我得到无限递归。

由于sub_ext是一个内部函数(我不会直接调用它,但是像knit之类的knitr函数都在内部调用它,我不能指望修改调用sub_ext手动调用new.sub_ext的所有函数,从而替换包命名空间中的定义。

1 个答案:

答案 0 :(得分:4)

执行assign('sub_ext', my.sub_ext, knitr)后,您将不可挽回地覆盖之前与sub_ext相关联的值,其值为my.sub_ext。但是,如果您首先存储原始值,则在完成后重置它并不困难:

library(knitr)
knitr <- asNamespace("knitr")

## Store the original value of sub_ext
.sub_ext <- get("sub_ext", envir = knitr)

## Overwrite it with your own function
my.sub_ext <- function (x, ext) "I'm in your package stealing your functions D:"
assignInNamespace('sub_ext', my.sub_ext, knitr)
knitr:::sub_ext("eg.csv", "pdf")
# [1] "I'm in your package stealing your functions D:"

## Reset when you're done
assignInNamespace('sub_ext', .sub_ext, knitr)
knitr:::sub_ext("eg.csv", "pdf")
# [1] "eg.pdf"   

或者,只要您只是添加代码行,就可以使用trace()添加代码。 trace()的好处是,当你完成后,你可以使用untrace()将函数的主体恢复为原始形式:

trace(what = "mean.default", 
      tracer = quote({
          a <- 1
          b <- 2
          x <- x*(a+b)
      }), 
      at = 1)
mean(1:2)
# Tracing mean.default(1:2) step 1 
# [1] 4.5
untrace("mean.default")
# Untracing function "mean.default" in package "base"
mean(1:2)
# [1] 1.5

请注意,如果您要跟踪的函数位于命名空间中,您将需要使用trace()的{​​{1}}参数,并将其传递给其他一些共享的(导出的)函数的名称待跟踪函数的命名空间。因此,要在 knitr 的命名空间中跟踪未导出的函数,可以设置where