用于分隔R中的环境的源脚本,而不是全局环境

时间:2016-09-21 15:24:25

标签: r r-environment

是否有办法source() R 中的脚本,以便将其作为父级附加到全局环境(.GlobalEnv)?

目前,当我提供脚本时,该脚本的所有变量和函数都出现在我的全局(交互式)环境中。我想在搜索路径中包含这些变量和函数,但不在.GlobalEnv中。也就是说,我希望源代码脚本的行为类似于附加的包,它附加在全局环境和基础环境之间(参见Advanced R Environments图)

enter image description here

5 个答案:

答案 0 :(得分:6)

最简单的方法来源脚本就好像它是一个包(即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)的环境,那么当您从脚本中调用该函数时,您将收到正确的错误:< / p>

# 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

答案 1 :(得分:4)

我还想使用sys.source函数的解决方案。使用envirtoplevel.env参数可以方便地(IMHO)绕过全局环境。根据链接文档:

  

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

答案 2 :(得分:3)

source文档中,local参数可以是一个确定源表达式求值位置的环境。

这表明您可以创建一个新环境,运行source将此环境传递给local,然后将attach环境传递到搜索路径。

或者您可以使用附加what=NULL创建一个空的环境,保存返回值,然后将其传递给local中的source

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

或作为一行:

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

答案 3 :(得分:2)

以下环境插入似乎可以实现所需的功能,但是,我不确定这是实现此目的的最佳方式:

检查当前搜索路径:

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

为源代码包添加新环境,并在local时使用source()参数:

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"

答案 4 :(得分:0)

我不确定我的答案是否与上面给出的答案有所不同,但是我使用以下代码:

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)