在R中,如何检查卸载包中是否存在函数?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在R中,如何检查卸载包中是否存在函数?相关的知识,希望对你有一定的参考价值。

我可以检查我的环境中是否存在一个函数:

> 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")
另一答案

好的,这需要更准确的答案。

简短版:你不能。

要了解原因,请考虑包中的以下代码:

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_alldevtools::unload做些更聪明的事,我不知道。

一些答案建议像try{package::foo}这样的东西。问题是这本身加载了命名空间:

> isNamespaceLoaded("broom")
[1] FALSE
> try(broom::tidy)
function(x, ...) UseMethod("tidy")
<environment: namespace:broom>
> isNamespaceLoaded("broom")
[1] 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))
    }
}

以上是关于在R中,如何检查卸载包中是否存在函数?的主要内容,如果未能解决你的问题,请参考以下文章

检查包中是不是存在文件

如何检查 scapy 数据包中是不是存在层?

R语言exists函数检查数据对象是否存在实战

如何检查特定文件是不是存在以及使用哪个退出代码?

R Shiny中是否存在全局变量?

如何检查刚体是否在移动?