当前位置 : 主页 > 网络推广 > seo >

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

来源:互联网 收集:自由互联 发布时间:2021-06-16
假设我替换了一个包的函数,例如knitr ::: sub_ext. (注意:我特别感兴趣的是它是一个内部函数,即只能通过:::访问,而不是::,但相同的答案可能适用于两者). library(knitr)my.sub_ext - function (x,
假设我替换了一个包的函数,例如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.

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

上面的问题是如果我不小心执行了两次(例如,它在我运行两次但没有重新启动R的脚本的顶部),第二次,original.sub_ext实际上是之前的new.sub_ext而不是真正的knitr ::: sub_ext,所以我得到了无限的递归.

由于sub_ext是一个内部函数(我不会直接调用它,但knitr的函数就像knit一样在内部调用它),我不能指望修改所有调用sub_ext的函数来手动调用new.sub_ext,因此这个方法替换包命名空间中的定义.

当你指定(‘sub_ext’,my.sub_ext,knitr)时,你不可避免地用my.sub_ext的值覆盖以前与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()的where参数,并将其传递给共享待跟踪函数命名空间的其他(导出)函数的名称.因此,要在knitr命名空间中跟踪未导出的函数,可以设置where = knit

网友评论