【问题标题】:R load libraries only in the local scopeR 仅在本地范围内加载库
【发布时间】:2020-11-15 04:32:18
【问题描述】:

是否可以让library() 仅影响本地范围?

例如,我的脚本有一个lapply 循环其他脚本中的source() 代码;这些脚本加载自己的库,但我希望在执行这些脚本中的代码后清理命名空间,以便脚本 1 调用的包 A 中的函数不会屏蔽脚本 2 调用的包 B 中的函数。

我知道有像 modulesimport 包这样的完整解决方案,但我希望首先使用更简单的基本 R 解决方案,以便仅在需要时进行扩展。

【问题讨论】:

  • 你不能只使用命名空间而不是调用library吗?
  • 什么意思?
  • Bakaburg,@AllanCameron 指的是您可以使用 foo 包中的函数 bar(),方法是使用 foo::bar() 而不是 library(foo); bar()
  • 它比这更复杂一些,我在一个临时函数中加载库,如果需要,它也会安装它们,所以这些库应该在这些脚本中定义。然后你可以说我不一定需要加载它们,但我想给这些脚本用户(那些将编写它们的人)编写easycode而不用命名空间的可能性(命名空间中的每个调用非常烦人) dplyr 管道)。
  • 您不能在单独的会话中执行这些脚本(而不是尝试在它们之后进行清理),例如使用callr 包吗?

标签: r scope package r-future


【解决方案1】:

使用loadNamespace("pkg") 将加载“pkg”包的命名空间。使用library("pkg") 还将附加 'pkg' 包到 R 的搜索路径。你可以看到使用loadedNamespaces() 加载了哪些命名空间,使用search() 附加了哪些包。这些属性对于 R 来说是全局的。换句话说,实际上不可能使它们成为局部的。

如果您希望在函数/map-reduce 调用中使用 library() 而没有 library() 导致包附加到您当前的 R 会话中,那么,正如其他人建议的那样,您可以在外部 R 中评估您的调用过程。

(免责声明:我是作者)我建议为此使用期货 (future),您可以通过 future.callr 在外部评估它们 - callr 的未来包装器。 未来的框架将负责将所需的对象导出到外部 R 进程。 这是一个例子:

library(future)
plan(future.callr::callr, workers = 1)
y <- lapply((1:3)/4, FUN = function(x) value(future({
  library(gtools)
  logit(x)
})))

注意未来是如何创建的,它的值是如何被立即检索的,即value(future(...))。为了澄清这一事实,您可以使用:

eval_via_future <- function(expr, substitute = TRUE, envir = parent.frame()) {
  if (substitute) expr <- substitute(expr)
  f <- future::future(expr, substitute = FALSE, envir = envir)
  future::value(f)
}
library(future)
plan(future.callr::callr, workers = 1)
y <- lapply((1:3)/4, FUN = function(x) eval_via_future({
  library(gtools)
  logit(x)
})))

如果您不想让用户指定plan(),您可以这样做:

eval_via_callr <- function(expr, substitute = TRUE, envir = parent.frame()) {
  oplan <- future::plan()
  on.exit(future::plan(oplan))
  future::plan(future.callr::callr, workers = 1)
  if (substitute) expr <- substitute(expr)
  f <- future::future(expr, substitute = FALSE, envir = envir)
  future::value(f)
}

所以你可以这样做:

y <- lapply((1:3)/4, FUN = function(x) eval_via_callr({
  library(gtools)
  logit(x)
}))

不加载或附加 gtools(它显然会加载 futurecallr 所需的其他包);

> loadedNamespaces()
 [1] "codetools"    "grDevices"    "listenv"      "future"       "ps"          
 [6] "memuse"       "clisymbols"   "prompt"       "digest"       "crayon"      
[11] "rappdirs"     "R6"           "future.callr" "datasets"     "utils"       
[16] "callr"        "graphics"     "base"         "tools"        "parallel"    
[21] "compiler"     "processx"     "stats"        "globals"      "methods"     

> search()
 [1] ".GlobalEnv"        "package:stats"     "package:graphics" 
 [4] "package:grDevices" "package:utils"     "package:datasets" 
 [7] "CBC tools"         "toolbox:default"   "package:methods"  
[10] "Autoloads"         "package:base" 

2020 年 7 月 26 日更新

以下是如何通过未来在外部 R 进程中获取 R 脚本,同时从主 R 会话中提取全局变量:

future_source <- function(file, envir = parent.frame(), ...) {
  expr <- parse(file = file, keep.source = FALSE)
  expr <- bquote({..(expr)}, splice = TRUE)
  future::future(expr, substitute = FALSE, envir = envir, ...)
}

source_via_callr <- function(file, envir = parent.frame()) {
  oplan <- future::plan()
  on.exit(future::plan(oplan))
  future::plan(future.callr::callr, workers = 1)
  f <- future_source(file, envir = envir)
  future::value(f)
}
## Two R scripts
cat("log(a)\n", file="a.R")
cat("library(gtools)\nlogit(a)\n", file="b.R")

## A global
a <- 0.42

## Source scripts in external process
y <- lapply(c("a.R", "b.R"), FUN = source_via_callr)

【讨论】:

  • 您好!谢谢你的重播。不幸的是,我无法使用我在脚本中声明的函数,为了使用它们,我不得不在表达式中再次 source() 脚本。没什么大不了的
  • 我试图将整个as.list(globalenv()) 传递给future() 的global 参数,但后来我得到了这个:Error in readLines(file, warn = FALSE) : 'con' is not a connection
  • 某些类型的对象仅在它们创建的 R 过程中才有意义。这包括 R 连接。无论并行化框架如何,这都是正确的——它们不能被导出到另一个 R 进程。有关详细信息和示例,请参阅未来的小插图“不可导出的对象”(cran.r-project.org/web/packages/future/vignettes/…)。
  • 我认为最好生成一个 minimal 可重现的示例 - 现在对你想要达到的目标(以及为什么)有太多的猜测 - 一个适当的代码示例将阐明这一点。
  • 我发现了问题:这是未来代码中的 source() 调用,它正在寻找定义的 file 变量(如果在其中定义了函数)。但是,它产生的不是“变量未找到错误”,而是上面的“'con'不是连接”。这是在我将 globalenv() 传递给未来时触发的,因为它正在替换定义 file 的父环境。
猜你喜欢
  • 2013-02-27
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多