简体   繁体   中英

How can I use get0 in my R package to search only within package namespace?

Let's say I have an internal function in my package, call it is_() , which can be thought of as a more generalized version if is() . In particular, it searches for specialized functions that are used to tell whether the supplied object is the given class. For example, is_() might be programmed as:

is_ <- function(obj, class) {
  if (exists(paste0("is.", class))) {
     get0(paste0("is.", class))(obj)
  }
  else inherits(obj, class)
}

That way, if I'm doing argument checking in my package, I can run something like

is_(x, "numeric_vector")

where I've defined

is.numeric_vector <- function(x) is.numeric(x) && is.null(dim(x))

within my package.

A problem arises when is.numeric_vector() is defined outside my package, eg, by another package the user has loaded. In that case, exists() and get0() both find the function wherever they can, but I want to restrict the search to function defined in my package and included in my package's namespace (ie, all imported packages). The envir and inherits arguments seem to get at what I want, but I don't know how to supply them to get the result I want. How can I restrict get0() to only search for its argument within my package's namespace?

The problem is that your package namespace will inherit from the base namespace which inherits from the global environment. For a more detailed explanation, see here: https://adv-r.hadley.nz/environments.html#namespaces . If you want more control over the symbol look up, you'll need to do the work yourself. You could include your own get function in your package

# These are private helpers that do not need to be exported from your package.
.pkgenv <- environment()
get1 <- function(name, env = .pkgenv) {
  if (identical(env, emptyenv())) {
    NULL
  } else if (identical(env, globalenv())) {
    # stop at global env
    NULL
  } else if (exists(name, envir=env, inherits = FALSE)) {
    env[[name]]
  } else {
    # try parent
    get1(name, parent.env(env))
  }
}

This will recursively search for the symbol in environments but stops at the global environment. You could use it with your is_ function like

is_ <- function(obj, class) {
  if (!is.null(fn <- get1(paste0("is.", class)))) {
    fn(obj)
  } else {
    inherits(obj, class)
  }
}

Here we just check for null rather than separately verifying the name and then retrieving the value. If get1 is something that will be called a bunch you might want to consider caching the result so you don't always have to walk the inheritance tree.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM