7

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

名前空間のインポート階層を理解する方法はありますか?もしそうなら、私は最後のループを正しく注文できるはずです...

4

2 に答える 2

0

確かに、ハッキーなニーズに対するハッキーなソリューションをまとめました。これをより良くする方法についてのアドバイスをいただければ幸いです。<<-特に、グローバル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)
}
于 2012-06-27T19:29:16.013 に答える
0

@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))
}
于 2012-06-27T19:41:14.133 に答える