2017-08-25 36 views
2

我正在寻找一种方法来调用不受.GlobalEnv中其他对象影响的函数。强制R函数调用是自给自足的

采取下面来看看两个功能:

y = 3 
f1 = function(x) x+y 

f2 = function(x) { 
    library(dplyr) 
    x %>% 
     mutate(area = Sepal.Length *Sepal.Width) %>% 
     head() 
} 

在这种情况下:

  • f1(5)应失败,因为y没有在功能范围
  • f2(iris)应该通过定义因为该函数没有引用其范围外的变量

现在,我可以覆盖的f1f2环境,无论是baseenv()new.env(parent=environment(2L))

environment(f1) = baseenv() 
environment(f2) = baseenv() 
f1(3) # fails, as it should 
f2(iris) # fails, because %>% is not in function env 

或:

# detaching here makes `dplyr` inaccessible for `f2` 
# not detaching leaves `head` inaccessible for `f2` 
detach("package:dplyr", unload=TRUE) 
environment(f1) = new.env(parent=as.environment(2L)) 
environment(f2) = new.env(parent=as.environment(2L)) 
f1(3) # fails, as it should 
f2(iris) # fails, because %>% is not in function env 

有没有办法来覆盖功能的环境,使其具有自给自足,但只要加载自己的库,它也总是有效的?

+1

只要是什么? –

+3

老实说,我只是不会编写包含全局变量的函数 - 它似乎是一个意外错误的处方。 –

+1

可能相关:https://stackoverflow.com/q/6216968/324364 – joran

回答

3

这里的问题是,从根本上,这library和类似的工具不提供作用域,而不是设计制造与范围的工作:即使library是在函数内部执行时,它的效果实际上是全球,而不是本地。 呃。

具体而言,您从全球环境中分离功能的方法是声音;然而,library操纵search路径(通过attach),并且该函数的环境未被“通知”:它仍将指向之前的第二个搜索路径条目作为其祖父。

当您调用library/attach/...时,您需要找到更新的方法。你可以用函数的父级环境中的library等替换你自己的版本来实现这个功能,这个版本调用attach的修改版本。这attach2然后不仅会调用原来的attach,但也重新链接您的环境的父母。


顺便说一句,‹modules›修复所有这些问题。在你的代码中用modules::import_package('foo', attach = TRUE)代替library(foo)使其工作。这是因为模块的作用范围很大,并且具有环境意识。

+0

是的,看起来没有别的办法。但为了这个工作,这个被重写的'library'版本需要被附加,我不确定我可以执行本地代码,因为潜在的非预期的副作用。 –