繁体   English   中英

R:我可以在不改变主环境的情况下运行 source() 的代码吗?

[英]R: Can I run source()’d code without altering the main environment?

在 R 中,我想要source()为其他目的编写的代码,以获取它创建的一些对象。 但是我不希望该源代码覆盖我的主程序中的对象,并且我不希望源代码加载可能屏蔽我在主程序中使用的函数的库(例如在 dplyr 之后加载 plyr 将如何屏蔽某些 dplyr 函数)。

在纯代码(没有source() 'd 代码)中,我可以在子环境中运行一些代码而不影响主环境对象,只需将选定的对象从子环境传递回主环境:

myGlobal <- "initial value"  # create an object in the main environment
objectsOfMyDesire <- with(new.env(), {
  myGlobal <- paste(myGlobal, "CHANGED by the with()"); message(paste0("in with(): myGlobal = ", myGlobal, "\""))  # alter object inherited from main environment
  mySub <- paste("mySub:", toupper(myGlobal)); message(paste0("in with(), mySub = ", mySub))    # create object
  return(list("mySub" = mySub))  # Return the created objects that I want to keep
})  # run code within a child environment, and return certain values to the main environment.

# Result: in the main environment, myGlobal is unchanged, mySub does not exist, but objectsOfMyDesire$mySub has been created
myGlobal; objectsOfMyDesire$mySub
mySub

但是当我获取相同的代码时,子环境中发生的一切都会影响主环境:

# Put code from within the "with()" above into a file, and then source() that file within a "with()":
rm(myGlobal, objectsOfMyDesire, mySub)
myTmpFile <- tempfile(pattern = "file", tmpdir = tempdir(), fileext = ".txt")
writeLines(con = myTmpFile, text = 'myGlobal <- paste(myGlobal, "CHANGED by the with()"); message(paste0("in with(): myGlobal = ", myGlobal));\n mySub <- paste("mySub:", toupper(myGlobal)); message(paste0("in with(), mySub = ", mySub))') 

# Having created a file to source(), run the example above, replacing some of the "with()" code with "source(myTmpFile)":
myGlobal <- "initial value"  # create an object in the main environment
objectsOfMyDesire <- with(new.env(), {
  source(myTmpFile)
  return(list("mySub" = mySub))  # Return the created objects that I want to keep
})  # run code within a child environment, and return certain values to the main environment.

# Result: in the main environment, myGlobal is CHANGED, mySub EXISTS, and objectsOfMyDesire$mySub has been created
myGlobal; objectsOfMyDesire$mySub
mySub

file.remove(myTmpFile)  # delete the temporary file

即使没有source() ,在with()创建的库仍然存在:

# For this test, use some function from some package that you have installed, but not loaded in this session
exists("summarize")
with(new.env(), {
  message(paste("\n\nin with(), exists(\"summarize\")=", exists("summarize"),"\n\n"))
  library(dplyr)  # load the package that contains the function
  message(paste("\n\nin with(), exists(\"summarize\")=", exists("summarize"),"\n\n")) })
exists("summarize")  # The package that was loaded in the child environment persists into the main environment. This is not good. I do not want anything from the child environment to persist unless I explicitly specify it. 
#unloadNamespace("dplyr")

那么,有没有什么方法可以从主程序中获取source()程序,而源程序不会影响主程序环境,而不仅仅是传回我明确指定的内容?

我找到了部分解决方案:

# Call the program that creates some objects I want to use in the current program.
#   Run it in a new, child environment that I'll name calledProgram, so that it will not affect objects in the main environment.
source(file=programFileAndPath, local = calledProgram <- new.env(), echo=T)
# The called programs objects are now in the calledProgram object.
#   So I now add code to bring the objects I wanted from the called program into the main environment.
usefulDataFrame <- calledProgram$usefulDataFrame
niceGGPlot      <- calledProgram$niceGGPlot
rm(calledProgram)  # I have moved the objects that I need into the main environment, so I now delete the calledProgram object

这不会保护会话的搜索路径或命名空间,因此如果源代码添加库、安装包或更改包版本,即使在运行此代码后,这些更改也会持续存在。 但至少这可以防止被调用的程序在主程序的环境中创建或更改对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM