在 R 中,如何检查卸载包中是否存在函数?
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
这不是一个很好的答案,它可能有一些缺陷,但它是一个开始。
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("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
的调用出错,它将 return FALSE;如果 fn
显示来源,TRUE
将被 returned。
> exists("zoo::is.zoo")
[1] FALSE
> exists_unloaded(zoo::is.zoo)
[1] TRUE
> exists_unloaded(zoo::is.zootoo)
[1] FALSE
(注意,所有字符串都写成 exists_unloaded
returns 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
您可以使用 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 代码了解这一点。
您可以检查 export(foo)
的 NAMESPACE 文件,但不幸的是,作者可能写了类似 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
我可以检查我的环境中是否存在函数:
> exists("is.zoo")
[1] FALSE
我可以通过加载包来检查函数是否存在:
> library(zoo)
> exists("is.zoo")
[1] TRUE
但是如何在 不加载 包的情况下检查包中是否存在函数?
> exists("zoo::is.zoo")
[1] FALSE
这不是一个很好的答案,它可能有一些缺陷,但它是一个开始。
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("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
的调用出错,它将 return FALSE;如果 fn
显示来源,TRUE
将被 returned。
> exists("zoo::is.zoo")
[1] FALSE
> exists_unloaded(zoo::is.zoo)
[1] TRUE
> exists_unloaded(zoo::is.zootoo)
[1] FALSE
(注意,所有字符串都写成 exists_unloaded
returns 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
您可以使用 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 代码了解这一点。
您可以检查 export(foo)
的 NAMESPACE 文件,但不幸的是,作者可能写了类似 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