【问题标题】:Force R function call to be self-sufficient强制 R 函数调用自给自足
【发布时间】:2017-08-25 21:42:55
【问题描述】:

我正在寻找一种方法来调用不受.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) 应该通过,因为该函数不会引用其范围之外的变量

现在,我可以将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

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

【问题讨论】:

  • 只要是什么?
  • 老实说,我根本不会编写包含全局变量的函数——这似乎是导致意外错误的秘诀。
  • @be_green 我有 99.9% 的把握相信迈克尔不仅知道这一点,而且非常同意这一点。我不知道问题的上下文,但我想这与在library that performs cross-machine communication 中隔离自包含用户代码有关。
  • @be_green 问题是特别注意全局变量的使用

标签: r scoping environments


【解决方案1】:

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

具体来说,您将函数与全局环境隔离的方法是声音;然而,library 操纵search 路径(通过attach),并且函数的环境没有“通知”这一点:它仍将指向 previous 第二个搜索路径条目它的祖父母。

library/attach/… 被调用时,你需要找到一种更新函数环境的祖父环境的方法。您可以通过将函数的父环境中的library 等替换为您自己的版本来实现此目的,该版本调用attach 的修改版本。这个attach2 不仅会调用原始的attach,还会重新链接您环境的父级。


1 顺便说一句,“box”解决了所有这些问题。在您的代码中将library(foo) 替换为box::use(foo[...]) 使其工作。这是因为模块是强作用域和环境感知的。

【讨论】:

  • 是的,看来没有别的办法了。但要使其正常工作,需要附加 library 的覆盖版本,由于潜在的意外副作用,我不确定我是否可以强制执行本地代码。
猜你喜欢
  • 2012-04-10
  • 1970-01-01
  • 2013-03-02
  • 2014-03-23
  • 1970-01-01
  • 2016-10-23
  • 2018-12-14
  • 2022-01-20
  • 1970-01-01
相关资源
最近更新 更多