Czy można mieć library() wpływają tylko na lokalny zakres?

Na przykład mój skrypt ma pętlę lapply, który kod źródłowy () w innych skryptach; Skrypty te ładują własne biblioteki, ale chciałbym wyczyszczenie przestrzeni nazw po wykonaniu kodu w tych skryptach, dzięki czemu funkcja w pakiecie A zwana skryptem 1 nie maskuje funkcje w pakiecie B wywoływane przez skrypt 2.

Wiem, że są kompletne rozwiązania, takie jak pakiet modules i import, ale chciałbym najprostszy roztwór bazowy R, aby skalować tylko w razie potrzeby.

1
Bakaburg 25 lipiec 2020, 15:26

1 odpowiedź

Najlepsza odpowiedź

Za pomocą loadNamespace("pkg") załaduje przestrzeń nazw pakietu "PKG". Korzystanie library("pkg") również Dołącz Pakiet "PKG" na ścieżkę wyszukiwania R. Możesz zobaczyć, które przestrzeń nazw są ładowane przy użyciu loadedNamespaces() i które pakiety są dołączone przy użyciu search(). Właściwości te są globalne do R. W innych słowach nie jest możliwe, aby uczynić je lokalnymi.

Jeśli chcesz użyć library() wewnątrz funkcji / mapy - zmniejszanie połączeń bez library() powoduje, że pakiet zostanie przymocowany w bieżącym sesji r, a następnie, jak inni sugerują, możesz ocenić swoje połączenia w zewnętrznym R proces.

(Zastrzeżenie: Jestem autorem) Proponuję używać futures ( przyszłość ) dla tego, gdzie oceniasz je zewnętrzne przez przyszłości Callr . przyszłe ramy zadbają o eksport obiektów potrzebnych do zewnętrznego procesu R. Oto przykład:

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

Zauważ, jak powstaje przyszłość, a jej wartość jest natychmiast pobierana, tj. value(future(...)). Aby wyjaśnić ten fakt, możesz użyć:

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)
})))

Jeśli chcesz uniknąć posiadania użytkownika określ plan(), co robisz:

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)
}

Więc możesz:

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

Bez ładowania lub mocowania Gtools (oczywiście ładuje inne pakiety potrzebne przez przyszłość i callr );

> 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" 

Aktualizacja 2020-07-26

Oto jak źródłowy skrypty w zewnętrznym procesie poprzez przyszłość, a jednocześnie ciągnąc globals z głównej sesji 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)
0
HenrikB 26 lipiec 2020, 17:37