knitr:如何实现编织代码的严格可复现性?
让knitr仅使用显式设置的编织变量
你碰到的这个问题本质是R环境的变量查找机制导致的:默认情况下用new.env()创建的环境会继承当前父环境的变量查找路径,所以哪怕你没在自定义环境里定义变量,knitr还是会偷偷往上找父环境里的同名变量,这就埋下了结果异常的隐患。
要彻底解决这个问题,关键是切断环境的继承链,让编织用的环境完全独立,只使用你显式设置的变量。
具体实现方法
创建环境的时候,指定parent = emptyenv(),这个参数会让新环境不继承任何上层环境的变量:
# 创建完全独立的空环境 e <- new.env(parent = emptyenv()) # 只添加你需要的编织变量 e$yes <- TRUE # 用这个环境执行编织 knit("foo.Rmd", envir = e)
验证效果
现在再测试你提到的场景:
e <- new.env(parent = emptyenv()) yes <- FALSE # 父环境的变量,不会被用到 knit("foo.Rmd", envir = e)
这时候就会触发你预期的Error in eval(expr, envir, enclos) : object 'yes' not found错误,而不是悄悄使用父环境的FALSE值,完美避免了变量冲突的问题。
原理补充
为什么之前的方法没生效?因为new.env()默认的parent参数是parent.frame()(也就是调用new.env()时的当前环境)。当Rmd代码在自定义环境里找不到变量时,会沿着环境链向上查找,直到找到变量或者到达空环境。而设置parent = emptyenv()直接把环境链的顶端设为空,没有上层环境可以查找,彻底杜绝了意外继承父环境变量的可能性。
内容的提问来源于stack exchange,提问作者antonio
相关产品推荐
相关产品推荐

