I can check that a function exists in my environment:
> exists("is.zoo")
[1] FALSE
I can check that a function exists after loading a package by loading it:
> library(zoo)
> exists("is.zoo")
[1] TRUE
But how can I check that a function exists in a package without loading that package?
> exists("zoo::is.zoo")
[1] FALSE
You can view the source of a function even if its not loaded.
> exists("zoo::is.zoo")
[1] FALSE
> zoo::is.zoo
function (object)
inherits(object, "zoo")
<environment: namespace:zoo>
So you could exploit that with a function like this
exists_unloaded <- function(fn) {
tryCatch( {
fn
TRUE
}, error=function(e) FALSE
)
}
If the call to fn
errors, it'll return FALSE; if fn
shows the source, the TRUE
will be returned.
> exists("zoo::is.zoo")
[1] FALSE
> exists_unloaded(zoo::is.zoo)
[1] TRUE
> exists_unloaded(zoo::is.zootoo)
[1] FALSE
(Just be careful, as written exists_unloaded
returns TRUE
for all strings. Probably want to error if fn
is a string.)
edit:
Also, you can call a function without loading the package. I don't know your full use case, but it might obviate the need to check for its existence. (Of course, if the user hasn't installed the package, it will still fail.)
> exists("zoo::is.zoo")
[1] FALSE
> zoo::is.zoo(1)
> z <- zoo::as.zoo(1)
> zoo::is.zoo(z)
[1] TRUE
If you didn't want to clutter the search path using loadNamespace
would work in conjunction with getAnywhere
Note that this will find functions unexported or exported...
loadNamespace('zoo')
x <- getAnywhere('is.zoo')
x[['where']]=='namespace:zoo'
# TRUE
Wrap it in a function
exist_pkg <- function(f, pkg){
loadNamespace(pkg)
x <- getAnywhere(f)
paste0('namespace:',pkg) %in% x[['where']]
}
you could be careful unloading namespaces afterwards if you really wanted
You could also use getFromNamespace
is.function(getFromNamespace("is.zoo", "zoo"))
# TRUE
It isn't a pretty answer, and it probably has some flaws to it, but it's a start.
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")
You can use the exists
function to look inside namespaces:
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))
}
}
OK, this needs a more accurate answer.
Short version: you can't.
To see why, consider the following code in a package:
eval(parse(text = paste0("foo <- func", "tion () 1 + 1")))
This will create a function foo
. But you will only learn that by running the R code.
You could check the NAMESPACE file for export(foo)
, but unfortunately the author might have written something like exportPattern("f.*")
, so that won't be reliable either.
Long version: you can't avoid loading the package, but you can avoid attaching it. In other words, R will interpret the package source files (and load any dlls), and will store the package in memory, but it won't be directly available on the search path.
ns <- loadNamespace(package)
exists("foo", ns)
You can then unload the namespace with unloadNamespace(package)
. But see the warnings in ?detach
: this is not always guaranteed to work! loadNamespace(package, partial = TRUE)
may be helpful, or maybe devtools::load_all
and devtools::unload
do something cleverer, I don't know.
Some answers are suggesting stuff like try{package::foo}
. The problem is that this itself loads the namespace:
> isNamespaceLoaded("broom")
[1] FALSE
> try(broom::tidy)
function(x, ...) UseMethod("tidy")
<environment: namespace:broom>
> isNamespaceLoaded("broom")
[1] TRUE
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.