我发现knitr文档继承了用户环境中的变量,即使envir = new.env()
提供了参数.如何防止它继承这些变量?
例如,假设我使用不存在的变量(y
)编写了一个简单的.Rmd文件,编织它并显示生成的文件:
library(knitr)
writeLines(c("```{r}", "y + 1", "```"), "test.Rmd")
knit("test.Rmd", quiet = TRUE, envir = new.env())
# [1] "test.md"
cat(readLines("test.md"), sep = "\n")
#
# ```r
# y + 1
# #> Error in eval(expr, envir, enclos): object 'y' not found
# ```
Run Code Online (Sandbox Code Playgroud)
当然,我得到一个错误,即y
变量不存在,就像我应该的那样.
但是,如果我y
在我自己的环境中定义,我发现我现在可以y
在.Rmd文件中引用,即使我给出了envir = new.env()
参数.
y <- 3
knit("test.Rmd", quiet = TRUE, envir = new.env())
# [1] "test.md"
cat(readLines("test.md"), sep = "\n")
#
# ```r
# y + 1
# # [1] 4
# ```
Run Code Online (Sandbox Code Playgroud)
我的理解是,envir = new.env()
应该导致knitr文档在没有y
变量的新环境中进行评估.这是一个问题,因为它允许knitr文档不可再现,指的是我没有在文档中定义的变量.
请注意,rmarkdown render
文档(它是一个包装器knit
)明确说明您可以使用envir = new.env()
:
在编织期间评估代码块的环境(可以使用new.env()来保证空的新环境).
但是,render
出于同样的原因,显示出与上述相同的行为.我的期望(和rmarkdown文档)是不正确的envir = new.env()
,还是我错误地使用它?还有另一种方法可以保证文档中的新环境被编织?
new.env
有一个parent
参数,其默认值是parent.frame()
- 即调用者.换句话说,您的新环境继承了当前环境中的所有内容.
您可以通过指定parent
:
new.env(parent = baseenv())
Run Code Online (Sandbox Code Playgroud)
或者,如果要继承已加载的包:
new.env(parent = as.environment(2))
Run Code Online (Sandbox Code Playgroud)
而且,是的,render
文档有点误导:虽然new.env()
提供了一个新的,空的环境,但它并没有完全与调用者分离,调用者可能几乎从不想使用它new.env()
.
为了能够在继承的干净环境中使用包baseenv()
,您需要手动实现包附件机制,因为R包本身不支持环境隔离(grrr!).或者您使用"modules"包,它支持本地连接的包:
```{r}
modules::import_package('ggplot2', attach = TRUE)
qplot(rnorm(10))
```
Run Code Online (Sandbox Code Playgroud)
该attach = TRUE
参数导致包本地附加,不像library
.
这是一个可以使用的"模块"包加载代码的精简版本:
require_namespace = function (package) {
ns = .Internal(getRegisteredNamespace(package))
if (is.null(ns))
ns = tryCatch(loadNamespace(package), error = identity)
ns
}
exhibit_package_namespace = function (namespace, name, parent, export_list) {
structure(list2env(sapply(export_list, getExportedValue, ns = namespace,
simplify = FALSE),
parent = parent.env(parent)),
name = paste('package', name, sep = ':'),
path = getNamespaceInfo(namespace, 'path'))
}
library_local = function (package, parent = parent.frame()) {
pkg_ns = require_namespace(package)
if (inherits(pkg_ns, 'error'))
stop('Unable to load package ', sQuote(package), '\n',
'Failed with error: ', sQuote(conditionMessage(pkg_ns)))
export_list = getNamespaceExports(pkg_ns)
pkg_env = exhibit_package_namespace(pkg_ns, package, parent, export_list)
parent.env(parent) = pkg_env
}
Run Code Online (Sandbox Code Playgroud)
用法:
```{r}
library_local('ggplot2')
qplot(rnorm(10))
```
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1120 次 |
最近记录: |