简体   繁体   English

“捕捉”全球环境

[英]“Capturing” the global environment

I'm using functions from an external package (that I cannot modify).我正在使用来自外部 package 的函数(我无法修改)。 These functions put a lot of stuff in the global environment, for instance the package does things like这些函数在全局环境中放置了很多东西,例如 package 做了类似的事情

the.data <<- data.frame(A=rnorm(10),B=rnorm(10),C=rnorm(10)) ## A sample dataset

package.plot <- function(){
  x.coords <<- the.data$A/the.data$B
  y.coords <<- the.data$C
  plot(x.coords, y.coords)
}

(obviously hyper-simplified example... here the key is that x.coods and y.coords are rather complex derivations, sufficiently complex that I do not want to recode them but find it advantageous to re-use the existing code) (显然是超简化的例子......这里的关键是 x.coods 和 y.coords 是相当复杂的派生,足够复杂以至于我不想重新编码它们但发现重用现有代码是有利的)

I want to use these functions in my own scripts, namely make the same graph with ggplot.我想在我自己的脚本中使用这些函数,即用 ggplot 制作相同的图表。 Of course, a first, obvious solution is当然,第一个明显的解决方案是

my.better.plot <- function(){
  package.plot()
  tibble(x.coords,y.coords) %>% ggplot(aes(x=x.coords,y=y.coords))+geom_point() # etc. 
}

However, this has two issues:但是,这有两个问题:

  1. I end up plotting twice (a minor issue, it is sufficiently fast to be unnoticeable);我最终绘制了两次(一个小问题,它足够快以至于不引人注意);
  2. I "pollute" the global environment with global x.coords and y.coords我用全局 x.coords 和 y.coords “污染”了全球环境

Hence, I would like to run package.plot() in a "pseudo-global" environment to avoid ending up with global variables that may be modified in an "uncontrolled" way.因此,我想在“伪全局”环境中运行 package.plot() 以避免最终得到可能以“不受控制”方式修改的全局变量。

A workaround, of course, is当然,一种解决方法是

my.better.plot <- function(){
  package.plot()
  tibble(x.coords,y.coords) %>% ggplot(aes(x=x.coords,y=y.coords))+geom_point() # etc. 
  rm(x.coords,envir=.GlobalEnv)
}

However, I'd prefer to do something like但是,我更愿意做类似的事情

my.better.and.cleaner.plot(){
  within.envir(dummy_env,my.better.plot)
}

.. assuming that there is, indeed, a function "within.envir" that allows to run its second argument in a mock global environment. .. 假设确实有一个 function "within.envir" 允许在模拟全局环境中运行它的第二个参数。

Is something like this possible at all?这样的事情可能吗? I did read http://adv-r.had.co.nz/Environments.html , but could not find the answer... (not one that I understood, at any rate).我确实读过http://adv-r.had.co.nz/Environments.html ,但找不到答案……(无论如何,我都没有理解)。 Bonus question: if this is possible, how can I extract the return value of ggplot from dummy_env and return it?奖励问题:如果可能的话,我怎样才能从 dummy_env 中提取 ggplot 的返回值并返回它?

So this is unfortunately very hacky, since the <<- operator will traverse the environment tree upwards if it does not find the variable name (hence why you should basically never use it. The one workaround is to call the function from another environment that already has the variables in question initialized. Then it will assign it into those variables and not traverse further up into the globalEnv. You need to know the variable names beforehand though.因此,不幸的是,这很 hacky,因为如果<<-运算符找不到变量名,它将向上遍历环境树(因此为什么您基本上不应该使用它。一种解决方法是从另一个已经已初始化有问题的变量。然后它会将其分配给这些变量,而不是进一步向上遍历到 globalEnv。不过,您需要事先知道变量名称。

f <- function(x) a <<- x
f(5)
# a = 5 in GlobalEnv
rm(a)
CapturedCall <- function(fun, CapturedVars,...)
{
  stopifnot(is.function(fun))
  SandBox <- new.env()
  for(varName in CapturedVars) assign(varName, NA,SandBox)
  environment(fun) <- SandBox
  fun(...)
}

CapturedCall(f,"a",1)
#Nothing in GlobalEnv

This function avoids the side effects as much as possible:这个function尽量避免了副作用:

  library(ggplot2)
  library(magrittr)
  library(tibble)
  my.better.plot <- function(){
    x.coords <- 1
    y.coords <- 1
    environment(package.plot) <- environment()
    
    bmp(tempfile())
    package.plot()
    dev.off()
    
    print(tibble(x.coords,y.coords) %>% ggplot(aes(x=x.coords,y=y.coords))+geom_point()) # etc. 
  }
  
  my.better.plot()
  #creates only the ggplot in the current device

  ls(globalenv())
  #[1] "my.better.plot" "package.plot"   "the.data" 

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

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