How can I reference the local environment within a function, in R?

22,694

To get the current environment, just call environment().

In general, sys.frame returns any of the environments currently on the call stack, and sys.nframe returns the current depth of the call stack. sys.frames returns a list of all environments on the call stack.

environment(f) returns the closure environment for a function f (where it will look for functions and global variables).

parent.env(e) returns the parent environment where it will look if a symbol is not found in e.

f <- function() {
  function() list(curEnv=environment(), parent=parent.env(environment()), 
          grandParent=parent.env(parent.env(environment())), callStack=sys.frames(), 
          callStackDepth=sys.nframe())
}
g <- function(f, n=2) if (n>2) g(f, n-1) else f()

floc <- f() # generate a local function
g(floc, 3) # call it

This will call the local function floc with a stack depth of 3. It returns a list with the current environment, it's parent (the local environment in f), and it's grand parent (where f was defined, so globalenv). It also returns the list of stack frames (environments). These are the environments for the recursive calls in g (except the last one which is the current environment of floc).

Share:
22,694
Iterator
Author by

Iterator

I noticed that this profile receives views. Let me make your click a little more worthwhile, and explain Iterator's raison d'être... I do some things again and again, or my code does (almost) the same thing again and again. Iterating isn't tedious per se, but it helps to iterate rapidly. I am mastering that. I work on topics in many areas, usually solving stimulating problems with stimulating data. Sometimes there is a stimulating amount of stimulating data. To contact me, look for me in the SO R chat room, where I am often learning from R experts, or leave a message there or in a separate chat (@Iterator) - SO will alert me.

Updated on February 09, 2020

Comments

  • Iterator
    Iterator about 4 years

    [This question has been resolved in the chat room, by Spacedman, but I'm posting it for others' benefit in the future.]

    I have a function, myFunc, which creates localFunc inside of it. (NB: this is not in a package, but in the global environment.) I'd like to know where localFunc exists in the search path, as I'd like to analyze it via mvbutils::foodweb.

    Here is an example:

    myFunc <- function(){
        require(data.table)
        require(mvbutils)
        localFunc <- function(x){
            return(as.data.table(x))
        }
        
        vecPrune <- c("localFunc",ls("package:data.table"))
        ix <- match("data.table",search())
        tmpWeb <- foodweb(where = c(1,ix), prune = vecPrune, plotting = FALSE)
        return(tmpWeb)
    }
    

    However, a call to myFunc() does not seem to indicate that localFunc calls data.table(). This is incorrect - what gives?

    (NB: The where argument specifies the search path.)


    Update 1: As Tommy and Spacedman point out, the trick is to specify environment(). The call to foodweb() refers to where = c(1, ix). The index 1 is a mistake. That arose from thinking that .GlobalEnv, which is often (always?) the first item in the search() vector, is the right place to search. That is erroneous. Instead, one should refer to environment(), and the correct call is below. (NB: ix specifies the location of data.table() in the search() output.)

    tmpWeb <- foodweb(where = c(environment(),ix), prune = vecPrune, plotting = FALSE)
    

    This appears in the answer to this question, in a function called checkScriptDependencies, which wraps the code from an R script file into a local function, which is then analyzed by foodweb. This is a limited example of how to use environment(), and Tommy has given a good explanation of how to use it and similar functions in this context.

  • Spacedman
    Spacedman over 12 years
    That's what I said in the chatroom. Now @iterator, give him the tick :)
  • Iterator
    Iterator over 12 years
    @Spacedman You had your chance. :) Tommy, thanks - your elaboration on what's going on is helpful. I knew the answer from Spacedman's chat comments, but didn't want to make the question self-answering. I was hoping that someone would come along with a more cogent explanation, as you have done.
  • qed
    qed almost 11 years
    curEnv is the same as callStack[[3]], parent and grandparent are totally different from the other callStacks, why?
  • Tommy
    Tommy almost 11 years
    Call stacks are the environments of all the callers, but that's NOT where variables are found. The parent environments are used for that - and they are linked together when the function is DEFINED, whereas calls stacks are linked together when the functions are CALLED. Tricky and confusing, I know...