【问题标题】:R Package development: overriding a function from one package with a function from another?R包开发:用另一个包中的函数覆盖一个包中的函数?
【发布时间】:2014-03-22 04:37:38
【问题描述】:

我目前正在开发两个包,下面是一个简化的 我的问题的版本:

在包 A 中,我有一些函数(比如“sum_twice”),它调用 包内的另一个函数(比如“slow_sum”)。 但是,在包 B 中,我编写了另一个函数(比如“fast_sum”),其中 我希望替换包 A 中的慢速功能。

现在,我如何使用 “fast_sum”函数?

以下是此类函数的简化示例(仅用于说明):

############################

##############
# Functions in package A

slow_sum <- function(x) {
sum_x <- 0
for(i in seq_along(x)) sum_x <- sum_x + x[i]
 sum_x
}

sum_twice <- function(x) {
x2 <- rep(x,2)
slow_sum(x2)
}

##############
# A function in package B
fast_sum <- function(x) { sum(x) }

############################

如果我只执行slow_sum &lt;- fast_sum 之类的操作,这将不起作用,因为“sum_twice”使用了 NAMESPACE 中的“slow_sum” 包A。

我在加载包“B”时尝试使用以下函数:

assignInNamespace(x = "slow_sum", value = B:::fast_sum, ns = "A")

这确实有效,但是,它使 CRAN 检查返回一个注释 我怎么不应该使用“:::”,以及使用assignInNamespace的警告 (因为它应该不是很安全)。

但是,我不知所措。 什么是让“sum_twice”使用“fast_sum”而不是 “慢和”?

感谢您的任何反馈或建议, 带着敬意, 塔尔

p.s:这是一个双重帖子from here.

UDPATE:这个问题的动机

我正在开发两个包,一个完全基于 R 并且工作正常(但有点慢),它是 dendextend(现在在 CRAN 上)。另一个旨在通过使用 Rcpp(这是 github 上的 dendextendRcpp)来加速第一个包。第二个包通过覆盖第一个包使用的一些基本功能来加速第一个包。但是为了让第一个包中的高级函数使用第二个包中的较低函数,我必须使用 assignInNamespace 导致 CRAN 抛出警告+注意,最终导致包被 CRAN 拒绝(直到这些警告将避免)。

问题是我不知道如何解决这个问题。我能想到的唯一解决方案是将两个包混合在一起(使其更难维护,并且会自动要求使用该包的人需要更大的依赖结构)。另一种选择是将更高级别的函数从dendextend复制粘贴到dendextendRcpp,从而让它们屏蔽其他函数。但我发现这不太优雅(因为这意味着我需要复制粘贴许多函数,从而强制进行更多的双重代码维护)。还有其他想法吗?谢谢。

【问题讨论】:

  • 即使您确实找到了这样做的方法,CRAN 也会返回某种警告或错误:否则您的包将能够更改任何其他已加载包的底层功能。
  • 你为什么要这样做?
  • Hadley - 我已经更新了这个问题的动机。感谢您的关注。
  • Scott,我们的想法是找到一种 CRAN 会尊重的方式。
  • 既然你自己维护这两个包:为什么不添加开关到dextended,如果它们可用的话,用快速函数覆盖慢速函数,例如,命名基于Rcpp的包foo_rcpp中的所有快速函数和然后有类似 if(require(dextendedRcpp)) foo

标签: r package


【解决方案1】:

我最终使用的解决方案(感谢 Uwe 和 Kurt)是使用“本地”来创建带有包选项的本地化环境。如果你好奇,这个函数叫做“dendextend_options”,在这里: https://github.com/talgalili/dendextend/blob/master/R/zzz.r

这是一个使用示例:

dendextend_options <- local({
   options <- list()
   function(option, value) {
      #          ellipsis <- list(...)         
      if(missing(option)) return(options)

      if(missing(value))
         options[[option]]
      else options[[option]] <<- value
   }
})
 dendextend_options("a")
 dendextend_options("a", 1)
 dendextend_options("a")
 dendextend_options("a", NULL)
 dendextend_options("a")
 dendextend_options()

【讨论】:

    【解决方案2】:

    我们可以把它放在sum_twice:

    my_sum_ch <- getOption("my_sum", if ("package:fastpkg" %in% search()) 
                           "fast_sum" else "slow_sum")
    my_sum <- match.fun(my_sum_ch)
    

    如果设置了"my_sum" 选项,则将使用该版本的my_sum,否则它将根据是否已加载 fastpkg 来做出决定。

    【讨论】:

      猜你喜欢
      • 2012-11-15
      • 1970-01-01
      • 2013-05-23
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-26
      • 2018-01-03
      • 1970-01-01
      相关资源
      最近更新 更多