Is there a way to source()
a script in R such that it is attached as a parent to the global environment (.GlobalEnv
)?
有没有办法在R中源()一个脚本,以便它作为父对象附加到全局环境(.GlobalEnv)?
Currently, when I source a script, all variables and functions of that script appear in my global (interactive) environment. I'd like to include these variables and functions in the search path, but not in .GlobalEnv
. That is, I'd like the sourced script to behave like an attached package, which gets attached between the global and base environments (see figure from Advanced R Environments)
目前,当我获取脚本时,该脚本的所有变量和函数都出现在我的全局(交互)环境中。我想在搜索路径中包含这些变量和函数,但不包含在.GlobalEnv中。也就是说,我希望源脚本的行为类似于附加的包,它附加在全局环境和基础环境之间(参见高级R环境中的图)
4 个解决方案
#1
3
From the source
documentation, the local
argument can be an environment which determines where the sourced expressions are evaluated.
从源文档中,local参数可以是一个确定源表达式求值位置的环境。
This suggests that you could create a new environment, run source
passing this environment to local
, then 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
in source
:
或者您可以使用attach with what = NULL来创建一个空的环境,保存返回值,并将其传递给源中的本地:
tmp <- attach(what=NULL)
source('test.R', local=tmp)
or as a single line:
或作为一行:
source('test.R', local=attach(NULL))
#2
3
The simplest way to source a script as if it was a package (i.e. such that lexical scoping won't result in the use of variables defined in the global environment when calling functions defined in your R script) is to create an environment that that is whose parent is the .BaseNamespaceEnv
, and then call source()
using that environment.
获取脚本的最简单方法就好像它是一个包(即,当调用R脚本中定义的函数时,词法作用域不会导致使用在全局环境中定义的变量)是创建一个环境,即其父级是.BaseNamespaceEnv,然后使用该环境调用source()。
For example if you have a script like this:
例如,如果您有这样的脚本:
# << my-script.R >>
my_fun <- function(x){x + y}
Then evaluating the following at the console, won't generate an error, as it would if my_fun
were defined within it's own package:
然后在控制台上评估以下内容将不会产生错误,因为如果在其自己的包中定义了my_fun:
source("my-script.R")
y = 2
my_fun(1)
#> 3
However, if you create an environment whose search()
path does not include the Global Environment (.GlobalEnv
) then you'll get a proper error when you call the function from your script:
但是,如果您创建一个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
#3
2
The following environment insertion appears to achieve the desired functionality, however, I'm not sure it's the best way to do this:
以下环境插入似乎可以实现所需的功能,但是,我不确定这是最好的方法:
Check the current search path:
检查当前搜索路径:
search()
# [1] ".GlobalEnv" "package:stats" "package:graphics"
# [4] "package:grDevices" "package:utils" "package:datasets"
# [7] "package:methods" "Autoloads" "package:base"
Add new environment for sourced packages and use local
parameter when source()
ing:
为源包添加新环境并在source()时使用local参数:
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"
Our script has added the dplyr
package to the search path, but note that "package:dplyr"
environment precedes the sourced script environment.
我们的脚本已将dplyr包添加到搜索路径,但请注意“package:dplyr”环境位于源脚本环境之前。
In order for sourced functions to be able to use dplyr (and any other packages), we remove the "sourced_script"
environment and reattach it at the front of the search path, ahead of the packages attached by the sourced script. Note: using attach()
to do this will not work because attach()
inserts a copy of the input environment (in this case, myEnv
).
为了使源代码函数能够使用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"
#4
2
I would also like to a solution using sys.source
function. Using envir
and toplevel.env
arguments allows for convenient (IMHO) bypassing of the global environment. As per the linked documentation:
我还想使用sys.source函数的解决方案。使用envir和toplevel.env参数可以方便地(恕我直言)绕过全局环境。根据链接文档:
sys.source
[p]arses expressions in the given file, and then successively evaluates them in the specified environment.sys.source [p]评估给定文件中的表达式,然后在指定的环境中连续评估它们。
tstEnv <- new.env()
sys.source(file = "tst.R", envir = tstEnv, toplevel.env = tstEnv)
where tst.R
contains:
其中tst.R包含:
a <- 1
b <- 1
Results:
ls(envir = .GlobalEnv)
# [1] "tstEnv"
ls(envir = tstEnv)
# [1] "a" "b"
tstEnv$a
# [1] 1
#1
3
From the source
documentation, the local
argument can be an environment which determines where the sourced expressions are evaluated.
从源文档中,local参数可以是一个确定源表达式求值位置的环境。
This suggests that you could create a new environment, run source
passing this environment to local
, then 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
in source
:
或者您可以使用attach with what = NULL来创建一个空的环境,保存返回值,并将其传递给源中的本地:
tmp <- attach(what=NULL)
source('test.R', local=tmp)
or as a single line:
或作为一行:
source('test.R', local=attach(NULL))
#2
3
The simplest way to source a script as if it was a package (i.e. such that lexical scoping won't result in the use of variables defined in the global environment when calling functions defined in your R script) is to create an environment that that is whose parent is the .BaseNamespaceEnv
, and then call source()
using that environment.
获取脚本的最简单方法就好像它是一个包(即,当调用R脚本中定义的函数时,词法作用域不会导致使用在全局环境中定义的变量)是创建一个环境,即其父级是.BaseNamespaceEnv,然后使用该环境调用source()。
For example if you have a script like this:
例如,如果您有这样的脚本:
# << my-script.R >>
my_fun <- function(x){x + y}
Then evaluating the following at the console, won't generate an error, as it would if my_fun
were defined within it's own package:
然后在控制台上评估以下内容将不会产生错误,因为如果在其自己的包中定义了my_fun:
source("my-script.R")
y = 2
my_fun(1)
#> 3
However, if you create an environment whose search()
path does not include the Global Environment (.GlobalEnv
) then you'll get a proper error when you call the function from your script:
但是,如果您创建一个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
#3
2
The following environment insertion appears to achieve the desired functionality, however, I'm not sure it's the best way to do this:
以下环境插入似乎可以实现所需的功能,但是,我不确定这是最好的方法:
Check the current search path:
检查当前搜索路径:
search()
# [1] ".GlobalEnv" "package:stats" "package:graphics"
# [4] "package:grDevices" "package:utils" "package:datasets"
# [7] "package:methods" "Autoloads" "package:base"
Add new environment for sourced packages and use local
parameter when source()
ing:
为源包添加新环境并在source()时使用local参数:
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"
Our script has added the dplyr
package to the search path, but note that "package:dplyr"
environment precedes the sourced script environment.
我们的脚本已将dplyr包添加到搜索路径,但请注意“package:dplyr”环境位于源脚本环境之前。
In order for sourced functions to be able to use dplyr (and any other packages), we remove the "sourced_script"
environment and reattach it at the front of the search path, ahead of the packages attached by the sourced script. Note: using attach()
to do this will not work because attach()
inserts a copy of the input environment (in this case, myEnv
).
为了使源代码函数能够使用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"
#4
2
I would also like to a solution using sys.source
function. Using envir
and toplevel.env
arguments allows for convenient (IMHO) bypassing of the global environment. As per the linked documentation:
我还想使用sys.source函数的解决方案。使用envir和toplevel.env参数可以方便地(恕我直言)绕过全局环境。根据链接文档:
sys.source
[p]arses expressions in the given file, and then successively evaluates them in the specified environment.sys.source [p]评估给定文件中的表达式,然后在指定的环境中连续评估它们。
tstEnv <- new.env()
sys.source(file = "tst.R", envir = tstEnv, toplevel.env = tstEnv)
where tst.R
contains:
其中tst.R包含:
a <- 1
b <- 1
Results:
ls(envir = .GlobalEnv)
# [1] "tstEnv"
ls(envir = tstEnv)
# [1] "a" "b"
tstEnv$a
# [1] 1