这既不是一个完全令人满意的答案,也是对@waterling 的长评论。
建议的解决方案是:
e<- new.env()
source("foo.R", local=e)
IE
source("foo.R", local=new.env())
这基本上等同于:
sys.source("foo.R", envir=new.env())
它的工作原理与以下原因大致相同:
sys.source("foo.R", envir=as.environment("package:grDevices"))
如错误报告(见问题),未找到函数,pdfFonts()
是包grDevices
的一部分sys.source
上面在环境中执行脚本package:grDevices
,因此找到了函数。相反,默认情况下sys.source(..., envir=baseenv())
,基础环境在 之前grDevices
,因此pdfFonts()
找不到。
第一个问题是我事先不知道哪些函数会出现在我的脚本中。在这种情况下,设置 envir=new.env()
是一种更通用的方法。默认情况下
new.env(parent=parent.frame())
,因此它具有相同的父级 sys.source()
,即全局环境。因此,全局环境中可见的所有内容都在脚本中可见sys.source(..., envir=new.env())
,即用户创建的每个对象以及用户加载的包。
这里的问题是我们不再隔离脚本,这使得它的可重复性和稳定性降低。事实上,这取决于我们调用的那一刻 R 内存中的内容sys.source
。为了使事情更实用,这意味着 foo.R
可能会起作用,因为我们通常在之后调用它bar.R
。
第二个问题是这不是一个实际的解决方案。问题涉及如何foo.R
在环境中运行脚本,e
并且在需要时仍然可以访问不属于e
. 获取 e
(直接或通过其父级)可以访问这些功能实际上是一种解决方法,而不是解决方案。
如果这种解决方法是唯一可行的方法,恕我直言,最好的办法是让它只依赖于标准的 R 包。
开始时,R 显示:
search()
## [1] ".GlobalEnv" "package:stats" "package:graphics"
## [4] "package:grDevices" "package:utils" "package:datasets"
## [7] "package:methods" "Autoloads" "package:base"
那是八个官方包/环境。
除非明确更改默认值,否则新的包/环境会进入第二个插槽,而第一个插槽之后的所有包/环境都会移动一个位置。
myEnv=new.env()
attach(myEnv)
search()
## [1] ".GlobalEnv" "myEnv" "package:stats"
## [4] "package:graphics" "package:grDevices" "package:utils"
## [7] "package:datasets" "package:methods" "Autoloads"
## [10] "package:base"
所以我们可以在搜索路径中取最后八个,这意味着取这八个中的第一个继承其他的。我们需要:
pos.to.env(length(search()) - 7)
## <environment: package:stats>
## attr(,"name")
## [1] "package:stats"
## attr(,"path")
## [1] "path/to//R/R-x.x.x/library/stats"
所以:
sys.source("foo.R", envir=new.env(parent=pos.to.env(length(search()) - 7)))
或者可以采用标准的 R 参考包,例如stats
及其父母。
所以:
sys.source("foo.R", envir=new.env(parent=as.environment("package:stats")))
更新
我找到了
解决方案
至于剧本:
#foo.R
#-----
library(extrafont)
f=function() loadfonts()
environment(f) = as.environment("package:extrafont")
f()
在新环境中执行:
sys.source("foo.R", envir=new.env(parent=baseenv()))
f()
现在可以访问包中的所有对象extrafont
以及之前加载的对象。
在 与任何父母一起sys.source()
创建任务时,分配工作new.env()
是必要的。environment()