Исходный скрипт для отдельной среды в R, а не глобальной среды

Есть ли способ source() скрипт в R такой, что он присоединен в качестве родителя к глобальной среде (.GlobalEnv)?

В настоящее время, когда я создаю сценарий, все переменные и функции этого сценария появляются в моей глобальной (интерактивной) среде. Я хотел бы включить эти переменные и функции в путь поиска, но не в .GlobalEnv, То есть я хотел бы, чтобы исходный сценарий вел себя как прикрепленный пакет, который подключается между глобальной и базовой средами (см. Рисунок из Advanced R Environments).

введите описание изображения здесь

4 ответа

Следующая вставка среды, кажется, для достижения желаемой функциональности, однако я не уверен, что это лучший способ сделать это:

Проверьте текущий путь поиска:

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

Добавить новую среду для пакетов и использовать local параметр, когда source()ING:

attach(new.env(), name="sourced_scripts")
myEnv <- as.environment("sourced_scripts")

source("some_other_script.R", local=myEnv)

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

Наш скрипт добавил dplyr пакет к пути поиска, но обратите внимание, что "package:dplyr" среда предшествует исходной среде сценария.

Чтобы функции из источника могли использовать dplyr (и любые другие пакеты), мы удаляем "sourced_script" окружение и присоедините его в начале пути поиска, перед пакетами, прикрепленными к исходному сценарию. Примечание: использование attach() сделать это не будет работать, потому что attach() вставляет копию среды ввода (в этом случае myEnv).

detach("sourced_scripts")
parent.env(myEnv) <- parent.env(.GlobalEnv)
parent.env(.GlobalEnv) <- myEnv
rm(myEnv)  # at this point we can remove myEnv to clear up namespace

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

Я также хотел бы, чтобы решение с использованием sys.source функция. С помощью envir а также toplevel.env Аргументы учитывают удобный (ИМХО) обход глобальной среды. Согласно связанной документации:

sys.source [p] оценивает выражения в заданном файле, а затем последовательно оценивает их в указанной среде.

tstEnv <- new.env()
sys.source(file = "tst.R", envir = tstEnv, toplevel.env = tstEnv)

где tst.R содержит:

a <- 1
b <- 1

Результаты:

ls(envir = .GlobalEnv)
# [1] "tstEnv"
ls(envir = tstEnv)
# [1] "a" "b"
tstEnv$a
# [1] 1

Самый простой способ создания сценария, как если бы он был пакетом (т. Е. Такой, чтобы лексическая область видимости не приводила к использованию переменных, определенных в глобальной среде при вызове функций, определенных в вашем сценарии R), - это создать среду, которая является чей родитель .BaseNamespaceEnv, а затем позвоните source() используя эту среду.

Например, если у вас есть такой скрипт:

# << my-script.R >>
my_fun <- function(x){x + y}

Тогда оценка следующего в консоли не выдаст ошибку, как если бы my_fun были определены в его собственном пакете:

source("my-script.R")
y = 2
my_fun(1)
#> 3

Тем не менее, если вы создаете среду, чья search() путь не включает глобальную среду (.GlobalEnv) тогда вы получите правильную ошибку при вызове функции из вашего скрипта:

# Create the environment:
ENV = new.env(parent = .BaseNamespaceEnv)
# Attache it to the search path so that objects in your environment can be
# found from the global environment (i.e. from the console):
attach(ENV)
# do things:
source("my-script.R",ENV)
y = 2
my_fun(1)
#> Error in .ENV$my_fun(3) : object 'y' not found

От source документация, local Аргумент может быть средой, которая определяет, где оцениваются исходные выражения.

Это говорит о том, что вы можете создать новую среду, запустить source передавая эту среду local, затем attach the environment to the search path.

Or you can use attach with what=NULL to create an empty environment, save the return value, and pass that to local в source:

tmp <- attach(what=NULL)
source('test.R', local=tmp)

или одной строкой:

source('test.R', local=attach(NULL))

Я не уверен, отличается ли мой ответ от ответов, приведенных выше, но я использую следующий код:

if (!exists('.env')) .env <- new.env() # creates an environment in which to store functions
if ('.env' %in% search()) detach(.env) # detaches .env if it already exists; does not "erase" functions previously stored in .env
func <- "filenameWhereSourceCodeIsStored"
source(paste0("C:/Users/JT/R/Functions/", func, ".R"), .env)
attach(.env)
Другие вопросы по тегам