将软件包附加到R中的“临时”搜索路径

问题描述

函数内部,我正在采购脚本:

quarkus.datasource.jdbc.driver

不幸的是,我所采购的脚本不受我的完全控制。他们呼叫f <- function(){ source("~/Desktop/sourceme.R") # source someone elses script # do some stuff to the variables read in } f() search() # library sourceme.R attaches is all the way in the back! ,并污染了搜索路径。

如果library(somePackage)的作者期望他/她所附加的软件包位于全球环境的最高层/顶部,那么这将是一个主要问题。如果我本人已经附上了一些掩盖了他/她期望可用的某些功能名称的软件包,那是不好的。

有没有办法获取脚本,但是以某种方式使我自己的临时搜索路径在函数完成运行后“重置”?

解决方法

我会考虑使用callr包在单独的R进程中采购脚本,然后返回由源文件创建的环境。

通过使用单独的R进程,可以防止您的搜索路径被污染。我猜想在您想要的全局环境中可能会有一些副作用(例如,定义变量的新函数)。 local函数的source自变量允许您指定应在何处执行已解析的脚本。如果从其他R进程返回此环境,则可以访问所需的任何结果。

不确定您的样子,但说我有这个文件会修改搜索路径:

# messWithSearchPath.R

library(dplyr)

a <- data.frame(groupID = rep(1:3,10),value = rnorm(30))

b <- a %>% 
  group_by(groupID) %>% 
  summarize(agg = sum(value))

在我的顶级脚本中,我将编写一个包装器函数以在新环境中获取它,并让callr执行该函数:

RogueScript <- function(){
  
  rogueEnv <- new.env()
  
  source("messWIthSearchPath.R",local = rogueEnv)
  
  rogueEnv
  
}

before <- search()

scriptResults <- callr::r(RogueScript)

scriptResults$b
#>   groupID       agg
#> 1       1 -2.871642
#> 2       2  3.368499
#> 3       3  1.159509

identical(before,search())
#> [1] TRUE

如果脚本还有其他副作用(例如设置选项或建立外部连接),则此方法可能无效。可能有变通办法,具体取决于它们要执行的操作,但是如果您只想创建变量/函数,则应该可以使用。它还可以防止脚本相互冲突,而不仅仅是顶级脚本。

,

一种方法是“快照”您当前的搜索路径,并稍后尝试返回它:

search.snapshot <- local({
  .snap <- character(0)
  function(restore = FALSE) {
    if (restore) {
      if (is.null(.snap)) {
        return(character(0))
      } else {
        extras <- setdiff(search(),.snap)
        # may not work if DLLs are loaded
        for (pkg in extras) {
          suppressWarnings(detach(pkg,character.only = TRUE,unload = TRUE))
        }
        return(extras)
      }
    } else .snap <<- search()
  }
})

实际情况:

search.snapshot()                                  # store current state
get(".snap",envir = environment(search.snapshot)) # view snapshot
#  [1] ".GlobalEnv"        "ESSR"              "package:stats"    
#  [4] "package:graphics"  "package:grDevices" "package:utils"    
#  [7] "package:datasets"  "package:r2"        "package:methods"  
# [10] "Autoloads"         "package:base"     
library(ggplot2)
library(zoo)
# Attaching package: 'zoo'
# The following objects are masked from 'package:base':
#     as.Date,as.Date.numeric
library(dplyr)
# Attaching package: 'dplyr'
# The following objects are masked from 'package:stats':
#     filter,lag
# The following objects are masked from 'package:base':
#     intersect,setdiff,setequal,union
search()
#  [1] ".GlobalEnv"        "package:dplyr"     "package:zoo"      
#  [4] "package:ggplot2"   "ESSR"              "package:stats"    
#  [7] "package:graphics"  "package:grDevices" "package:utils"    
# [10] "package:datasets"  "package:r2"        "package:methods"  
# [13] "Autoloads"         "package:base"     

search.snapshot(TRUE)                              # returns detached packages
# [1] "package:dplyr"   "package:zoo"     "package:ggplot2"

search()
#  [1] ".GlobalEnv"        "ESSR"              "package:stats"    
#  [4] "package:graphics"  "package:grDevices" "package:utils"    
#  [7] "package:datasets"  "package:r2"        "package:methods"  
# [10] "Autoloads"         "package:base"     

我有一点自信(未经验证),这可能并不总是适用于所有软件包,可能是由于依赖关系和/或加载的DLL。您可以尝试将force=TRUE添加到detach调用中,不确定这样做是否会更好,或者还有其他不良影响。