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