R:评估环境中的脚本

时间:2016-12-20 01:16:10

标签: r scope eval r-environment

我想在指定环境中评估的脚本中加载库函数。

示例:

## 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

1 个答案:

答案 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()分配工作。