簡體   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