问题描述
在R中,我想source()
出于其他目的而编写的代码,以获取其创建的某些对象。但是我不希望该源代码覆盖我的主程序中的对象,也不希望该源代码加载可能掩盖我在主程序中使用的函数的库(例如,在dplyr之后加载plyr将如何掩盖某些dplyr函数) )。
在普通代码中(没有source()
的代码),我可以在子环境中运行一些代码而不会影响主要环境对象,而只是将选定的对象从子环境中传递回主要环境:
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,myGlobal));\n mySub <- paste("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,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(),"\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
这不会保护会话的搜索路径或命名空间,因此如果源代码添加了库、安装包或更改包版本,即使在运行此代码后,这些更改也会持续存在。但这至少可以防止被调用的程序在主程序的环境中创建或更改对象。