2

我正在寻找一种方法来调用不受.GlobalEnv.

看看下面的两个函数:

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)应该通过,因为该函数不会引用其范围之外的变量

f1现在,我可以将and的环境覆盖f2baseenv()or 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

有没有办法覆盖函数的环境,使其必须自给自足,但只要它加载自己的库,它也总是可以工作?

4

1 回答 1

3

从根本上说,这里的问题是,library类似的工具不提供作用域,也不是为使用作用域而设计的:1即使library在函数内部执行,它的效果实际上是全局的,而不是局部的。啊。

具体来说,您将功能与全球环境隔离的方法是合理的;但是,library操作search路径(通过attach),并且函数的环境没有“通知”这一点:它仍将指向前一个第二个搜索路径条目作为其祖父母。

当调用 //…时,您需要找到一种方法来更新函数环境的祖父环境。您可以通过将函数的父环境中的 etc. 替换为您自己的版本来实现此目的,该版本调用. 然后,这不仅会调用原始环境,还会重新链接您环境的父级。libraryattachlibraryattachattach2attach


1顺便说一句,'<a href="https://klmr.me/box/" rel="nofollow noreferrer">box' 解决了所有这些问题。在您的代码中替换library(foo)box::use(foo[...])使其工作。这是因为模块是强作用域和环境感知的。

于 2017-08-26T08:59:35.303 回答