knitr inherits variables from a user's environment, even with envir = new.env()

后端 未结 2 1556
轮回少年
轮回少年 2020-12-30 05:57

I\'ve found that a knitr document inherits variables from the user\'s environment, even if the argument envir = new.env() is provided. How can I prevent it from

2条回答
  •  温柔的废话
    2020-12-30 06:21

    new.env has a parent argument whose default is parent.frame() — i.e. the caller. In other words, your new environment inherits all the stuff from your current environment.

    You can avoid this by specifying parent:

    new.env(parent = baseenv())
    

    Or, if you want to inherit loaded packages:

    new.env(parent = as.environment(2))
    

    And, yes, the render documentation is somewhat misleading: while new.env() provides a new, empty environment, it’s not entirely decoupled from the caller, and the caller probably almost never wants to use just new.env().

    In order to be able to use packages inside a clean environment inherited from baseenv(), you need to manually implement the package attachment mechanism because R packages do not support environment isolation by themselves (grrr!). Or you use the “modules” package, which supports locally attached packages:

    ```{r}
    modules::import_package('ggplot2', attach = TRUE)
    qplot(rnorm(10))
    ```
    

    The attach = TRUE argument causes the package to be attached locally, unlike library.

    Here’s a stripped-down version of the “modules” package loading code that could be used as well:

    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
    }
    

    Usage:

    ```{r}
    library_local('ggplot2')
    qplot(rnorm(10))
    ```
    

提交回复
热议问题