简体   繁体   English

Function里面一个function,访问之前的环境

[英]Function inside a function, access previous environment

I am trying to access a data frame created within a function and use its environment to access some data.我正在尝试访问在 function 中创建的数据框,并使用其环境来访问一些数据。 I know the ideal is to call it as an input in the function, but I am trying to avoid it, so I don't have to list hundreds of inputs.我知道理想的情况是将其称为 function 中的输入,但我试图避免它,因此我不必列出数百个输入。 Any help or resources are appreciated.任何帮助或资源表示赞赏。

An example is below:一个例子如下:

library(dplyr)

data_v1 <- tribble(~var1, ~var2,
                    1, 2)

postprocess_data <- function(){
  
  data_v3 <- data_v2 %>% 
    mutate(var2 = var2*3)
  
  data_v3
}


process_data <- function(){
  
  data_v2 <- data_v1 %>% 
    mutate(var1 = var1*3)
  
  data_v3_inside <- postprocess_data()
  
  data_v3_inside
    
}

process_data()

We can get the object from the parent.frame我们可以从 parent.frame 中得到parent.frame

postprocess_data <- function(){
  
  data_v2 <- get("data_v2", envir = parent.frame())
  data_v3 <- data_v2 %>% 
    mutate(var2 = var2*3)
  
  data_v3
}


process_data <- function(){
  
  data_v2 <- data_v1 %>% 
    mutate(var1 = var1*3)
  
  data_v3_inside <- postprocess_data()
  
  data_v3_inside
    
}

-testing -测试

process_data()
# A tibble: 1 × 2
   var1  var2
  <dbl> <dbl>
1     3     6

Your title describes the right way to do this.您的标题描述了执行此操作的正确方法。

Since process_data only needs to access data_v1 , it's fine as it is (though it would be better style if data_v1 was an argument).由于process_data只需要访问data_v1 ,它就这样很好(尽管如果data_v1是一个参数,它会更好)。

But postprocess_data needs access to data_v2 , a local variable in process_data .但是postprocess_data需要访问data_v2 ,这是process_data中的局部变量。 So the ideal design is to define postprocess_data inside process_data .所以理想的设计是在process_data中定义postprocess_data Then it will be able to see all of the variables that are local to process_data , as well as all global variables.然后它将能够看到process_data的所有本地变量,以及所有全局变量。 For example,例如,

library(dplyr)

data_v1 <- tribble(~var1, ~var2,
                    1, 2)


process_data <- function(){

  postprocess_data <- function(){
  
    data_v3 <- data_v2 %>% 
      mutate(var2 = var2*3)
  
    data_v3
  }


  data_v2 <- data_v1 %>% 
    mutate(var1 = var1*3)
  
  data_v3_inside <- postprocess_data()
  
  data_v3_inside
    
}

process_data()
#> # A tibble: 1 × 2
#>    var1  var2
#>   <dbl> <dbl>
#> 1     3     6

Created on 2022-03-23 by the reprex package (v2.0.1)reprex package (v2.0.1) 创建于 2022-03-23

Edited to add: There's one slightly risky thing in the way I wrote the code here.编辑添加:我在这里编写代码的方式有点冒险。

If you ever modified process_data() so that it called postprocess_data() before creating data_v2 , then the nested function would not find it in the enclosing environment, and would keep looking for it in the global environment.如果您曾经修改过process_data()以便它在创建data_v2之前调用postprocess_data() ,那么嵌套的 function 将不会在封闭环境中找到它,并且会继续在全局环境中寻找它。 If it happened to find a copy there you might end up with a subtle bug that caused you trouble.如果碰巧在那里找到一个副本,您可能会遇到一个给您带来麻烦的细微错误。

So a good idea is to create any variable used by the nested function very early, eg setting data_v2 <- NULL before the definition of postprocess_data .因此,一个好主意是尽早创建嵌套 function 使用的任何变量,例如在定义postprocess_data之前设置data_v2 <- NULL The NULL value should trigger an error if you haven't replaced it at the time you call the nested function.如果您在调用嵌套的 function 时没有替换它, NULL值应该会触发错误。

1) Assuming that you have control over and can modify process_data insert this as the first line of the body. 1)假设您可以控制并修改process_data ,将其插入正文的第一行。 That will make a copy of postprocess_data except its environment will be the frame within the running process_data so that any free variables in postprocess_data will be looked up there.这将制作postprocess_data的副本,除了它的环境将是正在运行的process_data中的框架,以便在那里查找postprocess_data中的任何自由变量。

environment(postprocess_data) <- environment()

2) If you don't have control over process_data and cannot change it but do have control over postprocess_data replace it with this. 2)如果您无法控制process_data并且无法更改它但可以控制postprocess_data将其替换为此。

  postprocess_data <- function(envir = parent.frame()) with(envir, {       
    data_v3 <- data_v2 %>% 
      mutate(var2 = var2*3)
  
    data_v3
  })

2a) or with this which makes it act sort of like a macro. 2a)或与此一起使它的行为有点像宏。

  postprocess_data <- function(envir = parent.frame()) eval(substitute({
  
    data_v3 <- data_v2 %>% 
      mutate(var2 = var2*3)
  
    data_v3
  }), envir = envir)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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