[英]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.