2012-06-27 27 views
6

中的名稱空間導入順序我需要清理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) 
    } 
} 

是否有某種方式來弄清楚命名空間層次進口?如果是這樣,那麼我應該能夠正確地命令最後一個循環...

+4

我很久以前就放棄了這個方法。 AFAIK,'detach'文件說它不能保證工作。唯一保證的方法是開始一個新的會話。 – Andrie

+0

是的,很遺憾,我無法在rpy2 AFAICT下啓動一個新的會話 - 這是一個Web應用程序,它在當前的設計中具有持續的R會話。 – Tarek

+1

繼續@安德烈的評論,最後幾個評論[這個SO問題]的答案(http://stackoverflow.com/questions/11004018/how-can-a-non-imported-method-in-a-沒有附加的包 - 被調用者找到樂趣)得到的原因之一就是「分離」不能可靠地將會話恢復到原始狀態。 –

回答

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

好吧,我已經把一個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) 
} 
+0

FWIW,在上面鏈接的例子中,這個* still *沒有去掉已經在'.__ S3MethodsTable__中註冊的以前連接包中的方法(在這種情況下,'gmodels'中的'reorder.factor()') 。仍然附加的軟件包(在這種情況下'stats')。 –

+0

謝謝你的澄清,喬希。幸運的是,這對我所做的事情已經足夠了,sgibb的答案比我的簡單得多。 – Tarek