[英]In R, how can I check for the existence of a function in an unloaded package?
我可以檢查我的環境中是否存在一個函數:
> exists("is.zoo")
[1] FALSE
加載包后,我可以檢查函數是否存在:
> library(zoo)
> exists("is.zoo")
[1] TRUE
但是如何在不加載該包的情況下檢查包中是否存在函數?
> exists("zoo::is.zoo")
[1] FALSE
即使未加載函數,也可以查看函數的來源。
> exists("zoo::is.zoo")
[1] FALSE
> zoo::is.zoo
function (object)
inherits(object, "zoo")
<environment: namespace:zoo>
所以你可以用這樣的函數來利用它
exists_unloaded <- function(fn) {
tryCatch( {
fn
TRUE
}, error=function(e) FALSE
)
}
如果調用fn
錯誤,它將返回FALSE; 如果fn
顯示源,則返回TRUE
。
> exists("zoo::is.zoo")
[1] FALSE
> exists_unloaded(zoo::is.zoo)
[1] TRUE
> exists_unloaded(zoo::is.zootoo)
[1] FALSE
(要小心,因為寫入的exists_unloaded
對於所有字符串都返回TRUE
。如果fn
是一個字符串,可能想要出錯。)
編輯:
此外,您可以在不加載包的情況下調用函數。 我不知道你的完整用例,但它可能不需要檢查它的存在。 (當然,如果用戶沒有安裝包,它仍然會失敗。)
> exists("zoo::is.zoo")
[1] FALSE
> zoo::is.zoo(1)
> z <- zoo::as.zoo(1)
> zoo::is.zoo(z)
[1] TRUE
如果您不想使用loadNamespace
混亂搜索路徑,則可以與getAnywhere
一起使用
請注意,這將找到未導出或導出的函數...
loadNamespace('zoo')
x <- getAnywhere('is.zoo')
x[['where']]=='namespace:zoo'
# TRUE
將它包裝在一個函數中
exist_pkg <- function(f, pkg){
loadNamespace(pkg)
x <- getAnywhere(f)
paste0('namespace:',pkg) %in% x[['where']]
}
如果你真的想要,你可以小心地卸載命名空間
您還可以使用getFromNamespace
is.function(getFromNamespace("is.zoo", "zoo"))
# TRUE
這不是一個很好的答案,它可能有一些缺陷,但它是一個開始。
is_exported <- function(fn, pkg){
nmsp <- readLines(system.file("NAMESPACE", package = pkg))
nmsp <- paste0(nmsp, collapse = " ")
Exports <- stringr::str_extract_all(nmsp,
stringr::regex("(?<=export[(]).+?(?=[)])"))
Methods <- stringr::str_extract_all(nmsp,
stringr::regex("(?<=S3method[(]).+?(?=[)])"))
any(grepl(stringr::regex(fn), c(Exports, Methods)))
}
is_exported("is.zoo", "zoo")
您可以使用exists
函數查看命名空間內部:
exists2 <- function(x) {
assertthat::assert_that(assertthat::is.string(x))
split <- base::strsplit(x, "::")[[1]]
if (length(split) == 1) {
base::exists(split[1])
} else if (length(split) == 2) {
base::exists(split[2], envir = base::asNamespace(split[1]))
} else {
stop(paste0("exists2 cannot handle ", x))
}
}
好的,這需要更准確的答案。
簡短版:你不能。
要了解原因,請考慮包中的以下代碼:
eval(parse(text = paste0("foo <- func", "tion () 1 + 1")))
這將創建一個函數foo
。 但是你只能通過運行R代碼來了解它。
您可以檢查NAMESPACE文件以進行export(foo)
,但遺憾的是作者可能編寫了類似exportPattern("f.*")
,因此也不可靠。
長版:你不能避免加載包,但你可以避免附加它。 換句話說,R將解釋包源文件(並加載任何dll),並將包存儲在內存中,但它不會直接在搜索路徑上可用。
ns <- loadNamespace(package)
exists("foo", ns)
然后,您可以使用unloadNamespace(package)
卸載命名空間。 但請參閱中的警告?detach
:這並不總能保證工作! loadNamespace(package, partial = TRUE)
可能會有所幫助,或者devtools::load_all
和devtools::unload
做一些更聰明的事情,我不知道。
一些答案建議像try{package::foo}
這樣的東西。 問題是這本身加載了命名空間:
> isNamespaceLoaded("broom")
[1] FALSE
> try(broom::tidy)
function(x, ...) UseMethod("tidy")
<environment: namespace:broom>
> isNamespaceLoaded("broom")
[1] TRUE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.