【问题标题】:How can I prevent `<<- ` from assigning in the global environment?如何防止`<<-`在全局环境中分配?
【发布时间】:2017-12-01 15:03:59
【问题描述】:

我收到了一个使用可怕的&lt;&lt;- 的函数。我有什么办法可以将它沙箱化,这样它就不会改变全球环境?

例如,我想找到一些东西,这样我就可以运行 f() 而不改变 x 的值:

x <- 0
f <- function()  x <<- 1
f()
x
# [1] 1

我尝试在已经定义了值的环境中对其进行评估:

local({
  x <- 2
  f()
})

但这似乎不起作用。有没有办法让我把它附上来保护地球环境?

【问题讨论】:

  • 用“
  • 此外,如果您获得的代码或多或少是独立的,您可以将其包装在一个包中并仅导出您需要的功能,那么x 应该在包命名空间中分配,除非导出。这将是最干净的解决方案。
  • ..或创建一个包含所有对象的 RDS/RData 文件,创建一个新会话,首先加载函数,然后加载二进制文件
  • @amonk,代码位于生产环境中使用的包中。更改此代码需要在服务器端进行更改,我还没有准备好。

标签: r


【解决方案1】:

assign &lt;&lt;- 函数将首先在父环境(该函数所在的那个)中查找,如果找不到,它将创建一个新的全局环境。

所以诀窍是将f() 包装在另一个函数中并在其中定义它,并且在这个包装函数中初始化一个变量x。那么它就不会从全球环境影响你的x

x <- 0
wrapped_f = function(){
  x<-2
  function()  x <<- 1
  f()
  print(paste("new x=", x))
}
wrapped_f()
#### "new x= 1"
print(x)
#### [1] 0

同样,但没有在包装器中初始化x,它将失败:

x <- 0
wrapped_f = function(){
  # x<-2
  f <- function()  x <<- 1
  f()
  print(paste("new x=", x))
}
wrapped_f()
#### "new x= 1"
print(x)
#### [1] 1

【讨论】:

  • 这简直是天方夜谭!
  • 感谢您的解释,我认为&lt;&lt;- 的赋值发生在调用环境中,而不是定义函数的环境中。现在一切都说得通了。
  • @snaut 实际上我在回答中做了一些精确的处理
【解决方案2】:

我们可以尝试使用exists 来检查该变量是否已在全局范围内定义。

f <- function()  {
   if(!exists("x"))
      x <<- 1
}
x <- 0
x
#[1] 0

f()

x
#[1] 0

【讨论】:

  • 如果 x 已经存在并且 f() 函数后面的一些代码需要它,它会返回错误 no?
  • @agenis 只是将赋值语句保留在 if 块中。其余的f() 代码应该在它之外,以便它可以在需要时访问x
【解决方案3】:

一种解决方法是使用生成器模式在单独的环境中定义函数。以下代码适用于我:

x <- -1
generator <- function(){
  x <- 0
  function()  x <<- 1
}

f <- generator()

f()
print(x)
# [1] -1

【讨论】:

  • 您的代码中定义的独立环境在哪里?
  • 生成器的本地环境。
  • 在您的示例中,您缺少 xfinal value 的输出。
  • 如果您以交互方式运行此代码,最后一行x 将打印x 的值,将其更改为打印。
猜你喜欢
  • 2020-07-23
  • 2011-09-09
  • 2019-07-16
  • 1970-01-01
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
相关资源
最近更新 更多