【问题标题】:Programmatically switch package in `::` call in R以编程方式在R中的`::`调用中切换包
【发布时间】:2019-06-13 15:41:40
【问题描述】:

给定对函数bar::foo() 的调用,我希望能够以编程方式切换包bar,以便相同的语法调用hello::foo()

一个例子

  • 假设我有三个包,parentPkgchildPkg1childPkg2
  • parentPkg 我有一个函数调用childPkg1::foo()
  • foo() 也是childPkg2 中的一个函数
  • 我希望能够在parentPkg 中使用:: 运算符调用foo(),但以编程方式切换包名称。 比如:

    dummy_pkg_name = ifelse(scenario=="child1", "childPkg1", "childPkg2")
    dummy_pkg_name::foo()
    

有可能吗?如何实现?

一些上下文

parentPkg 是一个与 Web 应用程序交互的函数,它接受一些请求和数据,并根据场景从不同的统计模型返回结果。
每个场景都非常复杂,并非所有内容都可以在parentPkg 中概括。出于这个原因,childPkg1childPkg2(实际上也有 3 和 4 个)是处理数据清理和每个场景的各种替代方案但返回相同类别的值的子包。
这个想法是,parentPkg 会根据场景将包切换到相关的子节点,并调用所有必要的函数,而不必为每个子节点编写相同的序列,只是使用稍微不同的 :: 调用。

【问题讨论】:

  • 我认为 if(requireNamespace('childPkg1')) 是你真正想要的

标签: r package


【解决方案1】:

由于::可以看成一个函数,所以看起来像

`::`(dummy_pkg_name, foo)()

是你想要的。或者,

getFromNamespace("foo", ns = dummy_pkg_name)()

例如,

`::`(stats, t.test)
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x102fd4b00>
# <environment: namespace:stats>

getFromNamespace("t.test", ns = "stats")
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x102fd4b00>
# <environment: namespace:stats>

【讨论】:

    【解决方案2】:

    要遵守KISS,只需在全局环境中重新分配给新的命名函数。请务必省略 (),因为您没有请求运行该功能。

    parent_foo <- parentPkg::foo
    child1_foo <- childPkg1::foo
    child2_foo <- childPkg2::foo
    child3_foo <- childPkg3::foo
    

    然后,根据需要有条件地应用它们:

    if (scenario=="child1") {
      obj <- child1_foo(...)
    } 
    else if (scenario=="child2") {
      obj <- child2_foo(...)
    } 
    ...
    

    【讨论】:

      【解决方案3】:

      您还可以创建一个call(),然后进行评估。

      call("::", quote(bar), quote(foo()))
      # bar::foo()
      

      投入使用:

      c <- call("::", quote(stats), quote(t.test))
      eval(c)
      # function (x, ...) 
      # UseMethod("t.test")
      # <bytecode: 0x4340988>
      # <environment: namespace:stats>
      

      使用setdiff 作为我们的默认函数包装在一个函数中:

      f <- function(pkg, fn = setdiff) {
          pkg <- substitute(pkg)
          fn <- substitute(fn)
          eval(call("::", pkg, fn))
      }
      
      f(base)
      # function (x, y) 
      # {
      #     x <- as.vector(x)
      #     y <- as.vector(y)
      #     unique(if (length(x) || length(y)) 
      #         x[match(x, y, 0L) == 0L]
      #     else x)
      # }
      # <bytecode: 0x30f1ea8>
      # <environment: namespace:base>
      
      f(dplyr)
      # function (x, y, ...) 
      # UseMethod("setdiff")
      # <environment: namespace:dplyr>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-02
        • 1970-01-01
        • 2010-09-27
        • 2015-03-21
        相关资源
        最近更新 更多