如何在加载时使变量对命名空间可用

How to make variable available to namespace at loading time

在我的一个包中,我使用 .onAttach 挂钩 运行 一些 R 代码,然后使用 assign 使该值可用作包变量之一。我这样做是因为 variable 取决于某个文件的内容,它可以在一个会话和另一个会话之间发生变化。我使用的代码是这样的:

.onAttach <- function(libname, pkgname) {
   variable <- some_function()
   assign("variable", variable, envir = as.environment("package:MyRPackage"))
}

当我用 library(MyRpackage) 附加包裹时,我可以使用 variable

但是不可能做类似MyRPackage::variable的事情(除非我已经用library(MyRpackage)附加了包裹。

我知道这是因为我应该将该代码放在 .onLoad 挂钩中,但是我无法进行分配以使其正常工作。

我试过了

.onLoad <- function(libname, pkgname) {
   variable <- some_function()
   assign("variable", variable, envir = as.environment("namesoace:MyRPackage"))
}

.onLoad <- function(libname, pkgname) {
   variable <- some_function()
   assign("variable", variable, envir = asNamespace("MyRPackage"))
}

但是当我 运行 MyRPackage:::variable 没有使用 library 附加包时,它们都失败并出现一些错误。

.onLoad hook 中的正确赋值是什么?

按照 中的方法解决相关问题,您可以像这样更改 .onLoad() 函数:

.onLoad <- function(libname, pkgname) {
    variable <- some_function()
    assign("variable", variable, envir = parent.env(environment()))
}

然后您可以访问 variable 而无需使用 MyRPackage:::variable 附加包。我不知道你用 some_function() 做了什么,所以我用一个虚拟包尝试了以下操作:

.onLoad <- function(libname, pkgname) {
    variable <- 42
    assign("variable", variable, envir = parent.env(environment()))
}

在新的 R 会话中,结果是

> MyRPackage:::variable
[1] 42

进一步说明

来自 Hadley Wickham 的 Advanced R:

There are four special environments:

...

  • The environment() is the current environment.

...

You can list the bindings in the environment’s frame with ls() and see its parent with parent.env().

因此,如果我们进一步修改 .onLoad() 函数,我们可以看到实际效果:

.onLoad <- function(libname, pkgname) {
    print(environment()) # For demonstration purposes only;
    print(parent.env(environment())) # Don't really do this.
    variable <- 42
    assign("variable", variable, envir = parent.env(environment()))
}

然后启动 R 会话会导致

<environment: 0x483da88>
<environment: namespace:MyRPackage>

在会话开始时打印到控制台。这允许您在环境 namespace:MyRPackage 中分配 variable,即使尝试 assign("variable", variable, envir = namespace:MyRPackage) 会导致错误

Error: package or namespace load failed for ‘MyRPackage’:

  .onLoad failed in loadNamespace() for 'MyRPackage', details:

  call: get(name, envir = ns, inherits = FALSE)

  error: object 'namespace' not found

安装包时。

基本上有两种方式:

  1. 通过assignInMyNamespace(…)
  2. 通过assign(…, envir = topenv())

虽然选项 1 看起来是 quite widespread,但它实际上需要更多代码,因为您首先需要创建一个变量,然后才能通过 assignInMyNamespace:

覆盖它
myvar = NULL

.onLoad = function (libname, pkgname) {
    assignInMyNamespace('myvar', value)
}

未能预先声明变量将导致错误。

相比之下,assign 完全有能力创建一个以前没有声明过的新变量。我们只需告诉 R 将变量分配到哪个环境中,函数 topenv() 提供了这一点。

.onLoad = function (libname, pkgname) {
    assign('myvar', value, envir = topenv())
}