簡體   English   中英

如何在[R]中確定命名空間導入順序

[英]How do I determine the namespace import order in [R]

我需要清理一個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)
    }
}

有沒有辦法找出命名空間導入層次結構? 如果是這樣,那么我應該能夠正確地訂購最后一個循環......

好吧,我已經把一個hacky解決方案歸結為一個公認的hacky需求。 任何有關如何做得更好的建議將不勝感激。 特別是,我對<<-賦值全局namespace_depths對象不太滿意。

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)
}

正如@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))
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM