我正在寻找一种调用不受 .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
和 f2
的环境覆盖为 baseenv()
或 new.env(parent =环境(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
有没有办法覆盖函数的环境,使其必须自给自足,但只要加载自己的库,它就始终可以工作?
最佳答案
从根本上来说,这里的问题是 library
和类似工具不提供作用域,并且并非设计用于使用作用域:1 即使library
是在函数内部执行的,它的作用实际上是全局的,而不是局部的。 呃。
具体来说,您将函数与全局环境隔离的方法是声音;然而,library
操纵 search
路径(通过 attach
),并且函数的环境不会“通知”这一点:它仍然会指向将前第二个搜索路径条目作为其祖 parent 。
您需要找到一种方法,在调用 library
/attach
/… 时更新函数环境的祖父环境。您可以通过将函数父环境中的 library
等替换为您自己的调用 attach
修改版本的版本来实现此目的。此attach2
不仅会调用原始attach
,还会重新链接您的环境的父环境。
1 顺便说一句,‘box ’解决了所有这些问题。在代码中将 library(foo)
替换为 box::use(foo[...])
即可使其正常工作。这是因为模块具有很强的作用域和环境感知能力。
关于r - 强制 R 函数调用自给自足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45889756/