Исходный скрипт для отдельной среды в 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)