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

问题描述 投票:0回答:2

在我的一个包中,我使用

.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 钩子中正确的赋值方式是什么?

r devtools r-package
2个回答
20
投票

按照相关问题的这个答案中的方法,您可以像这样更改您的

.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 的 高级 R

有四种特殊环境:

...

  • environment()是当前环境。

...

您可以使用 ls() 列出环境框架中的绑定 使用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>

在会话开始时打印到控制台。这允许您在环境

variable
中分配
namespace:MyRPackage
,即使尝试
assign("variable", variable, envir = namespace:MyRPackage)
会导致错误

错误:“MyRPackage”的包或命名空间加载失败:

  .onLoad 在“MyRPackage”的 loadNamespace() 中失败,详细信息:

  调用:get(名称,envir = ns,继承= FALSE)

  错误:找不到对象“命名空间”

安装软件包时。


3
投票

基本上有三种方式:

  1. 通过
    assignInMyNamespace(…)
  2. 通过
    assign(…, envir = topenv())
  3. 通过子集分配:
    ns$name = value

虽然选项 1 似乎相当普遍,但它实际上需要更多代码,因为您首先需要创建一个变量,然后才能通过

assignInMyNamespace
:

覆盖它
myvar = NULL

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

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

相比之下,

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

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

当然,如果我们定义一个命名空间对象并对其进行子集分配,则不需要

assign()
(或
assignInMyNamespace()
):

.onLoad = function (libname, pkgname) {
    ns = topenv()
    ns$myvar = value
}

对于我自己的代码,我倾向于最后一个选项。

© www.soinside.com 2019 - 2024. All rights reserved.