如何覆盖包命名空间中的不可见函数?

Posted

技术标签:

【中文标题】如何覆盖包命名空间中的不可见函数?【英文标题】:How do I override a non-visible function in the package namespace? 【发布时间】:2012-02-03 07:54:57 【问题描述】:

我基本上想更改一个包的不可见功能。对于可见函数,即在调用 methods 时没有星号的函数,我发现了两篇文章如何实现我的目标:

    使用assignInNamespace:见R-help上的帖子。 使用fix:见***上的帖子

虽然这两种方法都适用于导出/可见的函数(我使用predict.lm 作为下面的第二个方法的示例,并使用函数subset.data.frame 测试了第一种方法),但它们不适用于不可见的函数函数,例如predict.ar。这是为什么?有解决办法吗?

这是一个最小的例子:

显示 predict.lm 可见,predict.ar 不可见:

methods(predict)
 [1] predict.Arima*             predict.HoltWinters*       predict.StructTS*         
 [4] predict.ar*                predict.arima0*            predict.glm               
 [7] predict.lm                 predict.loess*             predict.mlm               
[10] predict.nls*               predict.poly               predict.ppr*              
[13] predict.prcomp*            predict.princomp*          predict.smooth.spline*    
[16] predict.smooth.spline.fit*

申请predict.lm:

x <- rnorm(5)
y <- x + rnorm(5)
predict(lm(y ~ x))
#          1          2          3          4          5 
#  1.0783047  1.5288031  0.3268405  0.8373520 -0.9833746

通过输入 cat("First line changed for predict.lm\n") 更改 predict.lm 在函数体的开头。 (您必须在编辑器中手动执行此操作):

fix(predict.lm)
predict(lm(y ~ x))
# First line changed for predict.lm
#          1          2          3          4          5 
#  1.0783047  1.5288031  0.3268405  0.8373520 -0.983374

申请predict.ar:

sunspot.ar <- ar(sunspot.year)
predict(sunspot.ar, n.ahead=25)
# $pred
# Time Series:
# Start = 1989 
# End = 2013 

尝试更改predict.ar

fix(predict.ar) #Here, an empty function body appears for me
fix("stats:::predict.ar") #Here as well
fix(stats:::predict.ar)
#Error in fix(stats:::predict.ar) : 'fix' requires a name

尝试改用assignInNamespace。 (注意,我只是在编辑器中复制了函数stats:::predict.ar,并在函数体的开头添加了cat("First line changed for predict.ar\n")这一行。由于函数体很长,这里只显示前几行)

mypredict <- function (object, newdata, n.ahead = 1, se.fit = TRUE, ...) 

    cat("First line changed for predict.ar\n")
    if (n.ahead < 1) 
        stop("'n.ahead' must be at least 1")
    #Rest of body of stats:::predict.ar

assignInNamespace("predict.ar", mypredict, ns="stats")
predict(sunspot.ar, n.ahead=25)
# First line changed for predict.ar
# Error in predict.ar(sunspot.ar, n.ahead = 25) : 
#   object 'C_artoma' not found

由于“First line changed for predict.ar”实际打印到控制台,因此 predict.ar 必须已更改。但是,为什么找不到对象“C_artoma”?

更新:好的,这太尴尬了,但我不能再删除那个帖子了:答案已经在我提供的链接中,最后是 Richie Cotton 的答案。很抱歉浪费您的时间!我想我检查了一切,然后我看不到明显的东西。有人可以将其发布为答案,我接受它。再次抱歉。

fixInNamespace(predict.ar, pos="package:stats")

【问题讨论】:

嘿,这个变化是永久性的吗?当我再次启动 R 并加载包时,更改会持续存在吗?对于 R6 类有没有办法,我正在寻找一种方法来修改包中定义的 R6 类。 【参考方案1】:

使用fixInNamespace。 :)

fixInNamespace("predict.ar", "stats")

fixInNamespace("predict.ar", pos="package:stats")

(几年后...) 来自 Nicholas H 的评论:如果你想将一些依赖于另一个包的内部函数的代码推送到 CRAN,它将引发构建警告并被 R-core 拒绝。如果你想要那个内部函数,你应该使用::: 操作符复制它并自己维护它。

predict.ar <- stats:::predict.ar

【讨论】:

好吧,我很生气自己没有在发布之前再次准确检查每个链接(*** 确实需要一个预览选项和对自己投反对票的选项......),但你实际上是一个给出正确答案的人让我很开心。所以谢谢你! @Christoph_J 我提供了一项收费的投票服务。如果你有兴趣... :) 好吧,我不会投票结束,因为这教会了我一些东西,而且@Richie Cotton 比我更了解 R。 @Dason,我最初的问题已经很老了。我发布了一个包(www.ggtern.com),它需要修补一些 ggplot2 函数以允许额外的维度和许多新的主题元素。对于一个非常具体的情况,即绘制三元图,我的包实际上是 ggplot2 的“扩展”。长话短说,assignInNamespace(...) 不能以任何方式使用。以下是关于我最终所做的一些附加信息:groups.google.com/forum/#!topic/ggplot2/SZX-SF9UCRo 出于某种原因,这似乎不适用于降价文档的上下文。 assignInNamespace() 确实做到了,尽管我确实必须使用 environment:::function() 表示法链接所有隐藏函数(在我想要替换的新版本函数中),并且有效。

以上是关于如何覆盖包命名空间中的不可见函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个包中只导入一个函数,而不加载整个命名空间

覆盖 gSOAP 中的命名空间

在 R 的命名空间中导入有啥好处?

处理 R 中冲突的命名空间(不同包中的相同函数名):重置包命名空间的优先级

PHP中的命名空间

从命名空间调用函数