【问题标题】:How do I determine the namespace import order in [R]如何确定 [R] 中的命名空间导入顺序
【发布时间】:2012-06-27 17:41:47
【问题描述】:

我需要清理一个 R 实例以使其恢复到启动时的原始状态。到目前为止,我正在做的是:

在启动时,记录加载的包和命名空间

original_packages <- grep('^package:', search(), value = TRUE)
original_namespaces <- loadedNamespaces()

当我需要刷新实例时,分离每个在启动时不存在的加载包:

for (pkg in grep('^package:', search(), value = TRUE)) {
    if (! pkg %in% original_packages){
        detach(pkg, unload=TRUE, force=TRUE, character.only=TRUE)
    }
}

问题是,如果我加载了一个包含一堆导入命名空间的包,例如 ggplot2,这些命名空间会保持加载状态,我必须按照导入的顺序从高层向下卸载它们。只是盲目地卸载它们是行不通的,因为我得到“命名空间‘x’是由‘y’导入的,‘z’所以不能卸载”错误。

这是可重现的示例:

original_packages <- grep('^package:', search(), value = TRUE)
original_namespaces <- loadedNamespaces()

library(ggplot2)
library(plyr)

loadedNamespaces()

for (pkg in grep('^package:', search(), value = TRUE)) {
    if (! pkg %in% original_packages){
        detach(pkg, unload=TRUE, force=TRUE, character.only=TRUE)
    }
}

for (ns in loadedNamespaces()) {
    if (! ns %in% original_namespaces){
        unloadNamespace(ns)
    }
}

有没有办法找出命名空间导入层次结构?如果是这样,那么我应该能够正确地订购最后一个循环......

【问题讨论】:

  • 我早就放弃了这种方法。 AFAIK,detach 的文档说它不能保证工作。唯一有保证的方法是开始一个新的会话。
  • 是的,很遗憾,我无法在 rpy2 AFAICT 下启动新会话 - 这是针对在当前设计中具有持久 R 会话的 Web 应用程序。
  • 跟进@Andrie 的评论,最后几个对this SO question 的回答得到了detaching 无法可靠地将您的会话恢复到其原始状态的原因之一。
  • 是的,我几乎放弃了detach()。现在,我正在尝试组合一个解决方案,该解决方案使用getNamespaceInfo() 来确定导入,并递归地通过这些来确定导入层次结构。然后,自下而上unloadNamespace()

标签: r ggplot2


【解决方案1】:

正如@Josh O'Brien 所说,通过分离或卸载命名空间是不可能获得干净的环境的。

但在这里回答您的问题是一种简单的方法,可以使用 tools:::dependsOnPkgs 以正确的顺序卸载所有命名空间:

## params: originalNamespaces is a list of namespaces you want to keep
cleanNamespaces <- function(originalNamespaces) {

    ## which namespaces should be removed?
    ns <- setdiff(loadedNamespaces(), originalNamespaces)

    ## get dependency list
    dep <- unlist(lapply(ns, tools:::dependsOnPkgs))

    ## append namespaces to guarantee to fetch namespaces with 
    ## no reverse dependencies
    ns <- c(dep, ns)

    ## get namespace names in correct order to unload without errors
    ns <- names(sort(table(ns), decreasing=TRUE))

    ## only unload namespaces which are attached
    ns <- ns[ns %in% loadedNamespaces()]

    ## unload namespaces
    invisible(sapply(ns, unloadNamespace))
}

【讨论】:

    【解决方案2】:

    好的,我已经为一个公认的 hacky 需求拼凑了一个 hacky 解决方案。任何有关如何更好地做到这一点的建议将不胜感激。特别是,我对全局 namespace_depths 对象的 &lt;&lt;- 分配不太满意。

    original_packages <- grep('^package:', search(), value = TRUE)
    original_namespaces <- loadedNamespaces()
    
    library(ggplot2)
    library(plyr)
    
    loadedNamespaces()
    
    new_packages <- Filter(function(pkg) { ! pkg %in% original_packages }, grep('^package:', search(), value = TRUE))
    
    new_namespaces <- Filter(function(ns) { ! ns %in% original_namespaces }, loadedNamespaces())
    
    get_imports <- function(ns, depth) {
    
        imports <- Filter(function(ns) { ! ns %in% original_namespaces }, names(getNamespaceInfo(ns, 'imports')))
        if (length(imports) == 0 ) {
            if ( is.null(namespace_depths[[ns]]) || namespace_depths[[ns]] < depth){
                namespace_depths[[ns]] <<- depth
            }
            return()
        }
        for (imported_ns in imports){
            get_imports(imported_ns, depth + 1)
        }
        if ( is.null(namespace_depths[[ns]]) || namespace_depths[[ns]] < depth){
            namespace_depths[[ns]] <<- depth
        }
    }
    
    namespace_depths <- list()
    sapply(new_namespaces, get_imports, 0)
    
    for (ns in names(namespace_depths)[order(unlist(namespace_depths))]) {
        if (! ns %in% original_namespaces){
            unloadNamespace(ns)
        }
    }
    
    for (pkg in new_packages){
        detach(pkg, unload=TRUE, force=TRUE, character.only=TRUE)
    }
    

    【讨论】:

    • FWIW,在我上面链接的示例中,这个 still 并没有摆脱以前附加的包中的方法(在这种情况下,reorder.factor() 来自 gmodels)已在仍附加的包的.__S3MethodsTable__.s 中注册(在这种情况下为stats)。
    • 感谢您的澄清,乔希。幸运的是,这对于我正在做的事情来说已经足够好了,而且 sgibb 的回答比我的要简单得多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 2013-04-24
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    相关资源
    最近更新 更多