我想在指定环境中评估的脚本中加载库函数。
示例:
## foo.R
## -----
## blah blah
library(extrafont)
loadfonts()
为方便起见,评估环境是基础环境:
sys.source("foo.R")
## Registering fonts with R
## Error in eval(expr, envir, enclos) : could not find function "loadfonts"
用loadfonts()
替换extrafont:::loadfonts()
效果更好,但仍然提供:
Error in get(as.character(FUN), mode = "function", envir = envir) :
object 'pdfFonts' of mode 'function' was not found
因为loadfonts()
需要在pdfFonts()
中定义grDevices
。
答案 0 :(得分:1)
对于@waterling来说,这是一个不完全令人满意的答案和长篇评论。
建议的解决方案是:
e<- new.env()
source("foo.R", local=e)
即。
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())
的脚本中可以看到全局环境中可见的所有内容,即用户和用户加载的包创建的每个对象。
这里的问题是我们不再使脚本绝缘,这使得它的可重现性和稳定性降低。实际上,它取决于我们调用sys.source
时的R内存中的内容。
为了使事情更实用,这意味着foo.R
可能只是因为我们通常在bar.R
之后调用它。
第二个问题是这不是一个实际的解决方案。
该问题涉及如何在环境foo.R
中运行脚本e
,并在需要时仍然可以访问不属于e
的函数。采用{{ (直接或通过其父母)访问这些功能实际上是一种解决方法,而不是解决方案。
如果这种类型的解决方法是唯一可行的方法,恕我直言,最好是使其仅依赖于标准R包。
在开始时,R显示:
e
这是八个官方包装/环境 新的软件包/环境,除非明确更改默认值,否则进入第二个插槽,第一个插槽后的所有插件移位一个位置。
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"
或者可以采用标准的R参考包,比如说sys.source("foo.R", envir=new.env(parent=pos.to.env(length(search()) - 7)))
及其父母。
因此:
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()
分配工作。