如果在函数内,evalq 如何在正确的环境中获取文件

Ber*_*ool 4 r

我有一个在其父环境中获取脚本的函数。以下内容按预期工作:

cat("aa <- 77", file="script.R")
runScript <- function() source("script.R", local=parent.frame())

env <- new.env()
evalq(runScript(), envir=env)
ls.str(envir=env) # as expected: aa in env, not in globalEnv
rm(env)
Run Code Online (Sandbox Code Playgroud)

当我将其包装在函数中时,环境似乎被忽略:

thisfails <- function(expr){
  env <- new.env()
  evalq(expr, envir=env)
  ls(envir=env)
}

thisfails(runScript()) # why is aa in globalEnv?
rm(aa)
Run Code Online (Sandbox Code Playgroud)

现在我可以用 来理解这一点eval,但不能用 来理解evalq,正如手册所说:eval 在将其传递给求值器之前评估当前作用域中的第一个参数: evalq 避免了这种情况。

有趣的是,这有效:

works <- function(){
  runScript()
  ls()
}
works() # as expected: returns aa, doesn't create it in globalEnv
Run Code Online (Sandbox Code Playgroud)

如何在函数内使用 runScript 作为表达式并避免在 globalEnv 中对其求值?

Kon*_*lph 5

这会失败,因为您的函数thisfails 本身正在使用标准评估:在传递给之前expr进行评估。evalq

\n

相反,您需要通过 捕获未计算的参数substitute,并将结果表达式传递给eval

\n
this_works <- function (expr) {\n  env <- new.env()\n  eval(substitute(expr), envir = env)\n  ls(envir = env)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

令人困惑的是,这看起来与evalq! \xe2\x80\x94\xc2\xa0 毕竟,evalq(expr)实现为:

\n
.Internal(eval(substitute(expr), envir, enclos))\n
Run Code Online (Sandbox Code Playgroud)\n

然而,认为等同evalq(expr)于 更为准确eval(quote(expr))。也就是说,逐字expr理解,并且从不评估。的实际实现看起来有所不同,只是因为它需要首先检索调用范围中由其参数表示的未计算表达式,而 \xe2\x80\x99 正是在参数上调用时执行的操作。evalqexprsubstitute

\n

\xe2\x80\xa6 令人困惑的是,对全局环境中的名称执行不同的substitute操作;也就是说,它让它们保持不变:

\n
x = 1\nsubstitute(x + 2)\n# x + 2\n\nin_function = function () {\n    x = 1\n    substitute(x + 2)\n}\n\nin_function()\n# 1 + 2\n\nin_env = new.env()\nin_env$x = 1\nsubstitute(x + 2, in_env)\n# 1 + 2\n
Run Code Online (Sandbox Code Playgroud)\n