如何在 R 包中使用 get0 仅在包命名空间内进行搜索?

How can I use get0 in my R package to search only within package namespace?

提问人:Noah 提问时间:4/1/2021 更新时间:4/1/2021 访问量:204

问:

假设我的包中有一个内部函数,称为 ,如果 .具体而言,它搜索用于判断所提供的对象是否为给定类的专用函数。例如,可以编程为:is_()is()is_()

is_ <- function(obj, class) {
  if (exists(paste0("is.", class))) {
     get0(paste0("is.", class))(obj)
  }
  else inherits(obj, class)
}

这样,如果我在我的包中进行参数检查,我可以运行类似的东西

is_(x, "numeric_vector")

我定义的地方

is.numeric_vector <- function(x) is.numeric(x) && is.null(dim(x))

在我的包裹里。

当在我的包之外定义时,例如,由用户加载的另一个包定义时,就会出现问题。在这种情况下,两者都尽可能地找到函数,但我想将搜索限制在我的包中定义并包含在我的包命名空间中的函数(即所有导入的包)。和 参数似乎得到了我想要的东西,但我不知道如何提供它们以获得我想要的结果。如何限制为仅在包的命名空间中搜索其参数?is.numeric_vector()exists()get0()envirinheritsget0()

R 命名空间 参数

评论

0赞 MrFlick 4/1/2021
您是否有一个您正在解决的函数冲突的实际示例,我们可以将其用于测试?
0赞 Noah 4/1/2021
要重现问题,请不要在包内定义,而是在包外(即在全局环境中)定义它。 会返回,但我希望它返回,因为是.is.numeric_vector()is_(1, "numeric_vector")TRUEFALSEinherits(1, "numeric_vector")FALSE

答:

1赞 MrFlick 4/1/2021 #1

问题在于,包命名空间将继承自从全局环境继承的基本命名空间。有关更详细的说明,请参阅此处:https://adv-r.hadley.nz/environments.html#namespaces。如果您想更好地控制符号查找,则需要自己完成这项工作。您可以在包中包含自己的函数get

# These are private helpers that do not need to be exported from your package.
.pkgenv <- environment()
get1 <- function(name, env = .pkgenv) {
  if (identical(env, emptyenv())) {
    NULL
  } else if (identical(env, globalenv())) {
    # stop at global env
    NULL
  } else if (exists(name, envir=env, inherits = FALSE)) {
    env[[name]]
  } else {
    # try parent
    get1(name, parent.env(env))
  }
}

这将在环境中递归搜索符号,但停止在全局环境中。您可以将它与您的函数一起使用,例如is_

is_ <- function(obj, class) {
  if (!is.null(fn <- get1(paste0("is.", class)))) {
    fn(obj)
  } else {
    inherits(obj, class)
  }
}

在这里,我们只检查 null,而不是单独验证名称,然后检索值。如果 is 将被称为一堆的东西,您可能需要考虑缓存结果,这样您就不必总是遍历继承树。get1

评论

0赞 Noah 4/1/2021
这很有帮助,谢谢。难道没有办法限制环境搜索使用它的和参数吗?如果用户附加了一个包含 的包,那么仍然不会选择它,因为它的环境是它来自的包而不是全局环境?get0()envirinheritsis_numeric_vector()is_()
0赞 MrFlick 4/1/2021
用户附加的包不应位于继承链中。如果您找到反例,请分享。没有办法改变 get0 的工作方式,因为这就是基础 R 的工作方式。如果您更喜欢手动迭代专利环境,您可以编写自己的专利环境。
0赞 Noah 4/1/2021
这发生在我自己的 R 包中,.我使用的函数类似于我在这里发布的函数,但替换为 .该软件包有一个函数 ,该函数会生成“已弃用”警告。当由用户附加并运行时,由 检索。您的解决方案不会阻止这种情况,因为不在全球环境中。WeightItis_()paste0("is.", class)paste0("is_", class)purrris_numeric()purrris_(x, "numeric")purrr:is_numeric()get0()purrr:is_numeric()
0赞 MrFlick 4/1/2021
还行。我把父订单弄错了,所以是的,附加的包成为全球环境的父级。因此,没有常见的方法可以停止在全球环境中进行搜索。我更新了我的答案,以使用另一种选择,这将停止在全球环境中。get0