【问题标题】:Convenience function for exporting objects to the global environment将对象导出到全局环境的便捷功能
【发布时间】:2023-03-23 10:52:01
【问题描述】:

更新:我添加了a variantRoland's implementationkimisc package

是否有将对象导出到全局环境的便捷函数,可以从函数中调用该函数以使对象全局可用?

我正在寻找类似的东西

export(obj.a, obj.b)

表现得像

assign("obj.a", obj.a, .GlobalEnv)
assign("obj.b", obj.b, .GlobalEnv)

基本原理

我知道<<-assign。我需要这个来重构旧代码,这只是脚本的串联:

input("script1.R")
input("script2.R")
input("script3.R")

script2.R 使用来自script1.R 的结果,而script3.R 可能使用来自12 的结果。这会创建一个严重污染的命名空间,我想更改每个脚本

pollute <- the(namespace)
useful <- result

(function() {
pollute <- the(namespace)
useful <- result
export(useful)
})()

作为第一个廉价的对策。

【问题讨论】:

  • 你的编辑让我迷失了。你有连接脚本,你想重构它们。如何 ?有用的是脚本还是脚本的结果?抱歉,我不明白你的理由。
  • 我又试了一次,但可能还是不明白你的用例。
  • 一个密切相关的事情:假设导出的对象要包含在一个包的导出对象中。这可以用 roxygen2 来完成,而无需手动编写大量样板文件#' @export 吗?参照。 stackoverflow.com/questions/39917807/…

标签: r convenience-methods


【解决方案1】:

只需编写一个包装器:

myexport <- function(...) {
  arg.list <- list(...)
  names <- all.names(match.call())[-1]
  for (i in seq_along(names)) assign(names[i],arg.list[[i]],.GlobalEnv)
}

fun <- function(a) {
  ttt <- a+1
  ttt2 <- a+2
  myexport(ttt,ttt2)
  return(a)
}

print(ttt)
#object not found error
fun(2)
#[1] 2
print(ttt)
#[1] 3
print(ttt2)
#[1] 4

没有经过彻底测试,也不确定这有多“安全”。

【讨论】:

  • 查看我的编辑以更好地解释我在寻找什么。
  • @Thomas:这是否意味着assign(..., .GlobalEnv) 通常更健壮?
  • Roland:是的,这就是我想要的。我只是想知道是否有人以前做过努力并将这样的功能放入 R 包中。否则,如果您允许,我会将其放入我自己的 this-and-that package 中。
  • 我不介意你把它放在你的包裹里,但正如我提到的,它并没有真正经过测试。
  • 我已将a variant of your implementation 添加到我的package
【解决方案2】:

您可以创建一个环境变量并在导出函数中使用它。例如:

env <- .GlobalEnv      ## better here to create a new one :new.env()
exportx <- function(x)
{
  x <- x+1
  env$y <- x
}

exportx(3)
y
[1] 4

例如,如果你想在你的包中定义一个全局选项(模仿经典的 R 选项),

my.options <- new.env()
setOption1 <- function(value) my.options$Option1 <- value

编辑在 OP 澄清后:

你可以使用evalq,它有两个参数:

envir 评估 expr 的环境 在其中 R 查找未在环境中找到的对象。

这里是一个例子:

env.script1 <- new.env()
env.script2 <- new.env()
evalq({
  x <- 2
  p <- 3 
  z <- 5 
} ,envir = env.script1,enclos=.GlobalEnv)

evalq({
  h <- x +2
} ,envir = env.script2,enclos=myenv.script1)`

您可以看到所有变量都是在环境中创建的(如local

 env.script2$h
[1] 4
env.script1$p
[1] 3
> env.script1$x
[1] 2

【讨论】:

    【解决方案3】:

    首先,鉴于您的用例,我看不出export 函数比使用好的(?)老式&lt;&lt;- 更好。你可以这样做

    (function() {
        pollute <- the(namespace)
        useful <<- result
    })()
    

    这将给出与您的示例相同的结果。

    其次,使用local 似乎比使用匿名函数更好,它允许您运行相关的计算,而不会在您的工作空间中乱扔各种临时对象。

    local({
        pollute <- the(namespace)
        useful <<- result
    })
    

    ETA:如果出于某种原因避免修改名为useful 的现有变量很重要,请在此处输入exists。这同样适用于提出的其他解决方案。

    local({
        .....
        useful <- result
        if(!exists("useful", globalenv())) useful <<- useful
    })
    

    【讨论】:

    • 1.如果useful 已经在环境中定义了怎么办? 2. 感谢local 的提示,确实比匿名函数调用更具可读性。但我仍然需要一个export 函数...
    • 这里给出的所有其他解决方案也将丢弃现有版本的useful。你没有意识到吗?
    • 我不介意在全球环境中覆盖useful。但是如果useful也存在于本地环境中呢? assign 在这种情况下不是更健壮吗?
    • 如果useful在包环境中,默认情况下它的值会被锁定(不能改变)。在这种情况下,&lt;&lt;- 将在全局环境中进行分配。见?&lt;&lt;-
    • 但是如果目标是分配给全局环境&lt;&lt;-是不精确的;它不是全局赋值运算符,如果在本地使用的函数中使用,例如 useful,可能会产生意想不到的结果。
    猜你喜欢
    • 2014-02-06
    • 2015-11-10
    • 1970-01-01
    • 2019-12-16
    • 2018-12-23
    • 2017-12-30
    • 1970-01-01
    • 2020-05-27
    • 2018-10-27
    相关资源
    最近更新 更多