在 R 中分离环境的源脚本,而不是全局环境
Source script to separate environment in R, not the global environment
有没有办法 source()
R 中的脚本,使其作为父级附加到全局环境 (.GlobalEnv
)?
目前,当我获取一个脚本时,该脚本的所有变量和函数都会出现在我的全局(交互式)环境中。我想在搜索路径中包含这些变量和函数,但不在 .GlobalEnv
中。也就是说,我希望源脚本表现得像一个附加包,附加在全局环境和基本环境之间(参见 Advanced R Environments 中的图)
以下环境插入似乎可以实现所需的功能:
查看当前搜索路径:
search()
# [1] ".GlobalEnv" "package:stats" "package:graphics"
# [4] "package:grDevices" "package:utils" "package:datasets"
# [7] "package:methods" "Autoloads" "package:base"
为源包添加新环境并在 source()
ing:
时使用 local
参数
myEnv <- new.env()
source("some_other_script.R", local=myEnv)
attach(myEnv, name="sourced_scripts")
检查搜索路径:
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"
请注意,我们attach()
新环境在 sourcing 之后,因此dplyr
附加在搜索路径中我们的脚本环境之后。
根据 source
文档,local
参数可以是一个环境,它确定在何处计算源表达式。
这表明您可以创建一个新环境,运行 source
将此环境传递给 local
,然后 attach
将环境传递给搜索路径。
或者您可以使用附加 what=NULL
创建一个空环境,保存 return 值,并将其传递给 source
中的 local
:
tmp <- attach(what=NULL)
source('test.R', local=tmp)
或单行:
source('test.R', local=attach(NULL))
最简单的脚本来源方式,就好像它是一个包(即这样 lexical scoping 不会导致在调用 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
我还想要一个使用 sys.source
函数的解决方案。使用 envir
和 toplevel.env
参数可以方便地(恕我直言)绕过全局环境。根据链接文档:
sys.source
[p]arses expressions in the given file, and then
successively evaluates them in the specified environment.
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
我不确定我的答案是否与上面给出的答案有任何不同,但我使用以下代码:
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)
有没有办法 source()
R 中的脚本,使其作为父级附加到全局环境 (.GlobalEnv
)?
目前,当我获取一个脚本时,该脚本的所有变量和函数都会出现在我的全局(交互式)环境中。我想在搜索路径中包含这些变量和函数,但不在 .GlobalEnv
中。也就是说,我希望源脚本表现得像一个附加包,附加在全局环境和基本环境之间(参见 Advanced R Environments 中的图)
以下环境插入似乎可以实现所需的功能:
查看当前搜索路径:
search()
# [1] ".GlobalEnv" "package:stats" "package:graphics"
# [4] "package:grDevices" "package:utils" "package:datasets"
# [7] "package:methods" "Autoloads" "package:base"
为源包添加新环境并在 source()
ing:
local
参数
myEnv <- new.env()
source("some_other_script.R", local=myEnv)
attach(myEnv, name="sourced_scripts")
检查搜索路径:
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"
请注意,我们attach()
新环境在 sourcing 之后,因此dplyr
附加在搜索路径中我们的脚本环境之后。
根据 source
文档,local
参数可以是一个环境,它确定在何处计算源表达式。
这表明您可以创建一个新环境,运行 source
将此环境传递给 local
,然后 attach
将环境传递给搜索路径。
或者您可以使用附加 what=NULL
创建一个空环境,保存 return 值,并将其传递给 source
中的 local
:
tmp <- attach(what=NULL)
source('test.R', local=tmp)
或单行:
source('test.R', local=attach(NULL))
最简单的脚本来源方式,就好像它是一个包(即这样 lexical scoping 不会导致在调用 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
我还想要一个使用 sys.source
函数的解决方案。使用 envir
和 toplevel.env
参数可以方便地(恕我直言)绕过全局环境。根据链接文档:
sys.source
[p]arses expressions in the given file, and then successively evaluates them in the specified environment.
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
我不确定我的答案是否与上面给出的答案有任何不同,但我使用以下代码:
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)