R scoping:禁止函数中的全局变量

时间:2015-03-10 18:04:39

标签: r scope global

如果在R函数中使用全局变量,有没有办法抛出警告(并失败..)?我认为这样可以避免意外行为......例如。

sUm <- 10
sum <- function(x,y){
sum = x+y
return(sUm)
}

由于返回“拼写错误”,该函数将始终返回10。它应该失败,而不是返回sUm的值。

5 个答案:

答案 0 :(得分:8)

我的另一个答案更多的是关于你可以在你的功能中采取什么方法。现在,我将提供一些关于在定义函数后要做什么的见解。

为了确保您的功能在不应该使用全局变量时,请使用codetools包。

library(codetools)

sUm <- 10
f <- function(x, y) {
    sum = x + y
    return(sUm)
}

checkUsage(f)

这将打印消息:

  

<anonymous> local variable ‘sum’ assigned but may not be used (:1)

要查看函数中是否使用了任何全局变量,可以将findGlobals()函数的输出与全局环境中的变量进行比较。

> findGlobals(f)
[1] "{"  "+"  "="  "return"  "sUm"

> intersect(findGlobals(f), ls(envir=.GlobalEnv))
[1] "sUm"

这告诉你全局变量sUmf()内部使用时可能不应该。

答案 1 :(得分:5)

无法永久更改变量的解析方式,因为这会破坏很多功能。在许多情况下,您不喜欢的行为实际上非常有用。

如果在函数中找不到变量,R将检查为这样的变量定义函数的环境。您可以使用environment()功能更改此环境。例如

environment(sum) <- baseenv()
sum(4,5)
# Error in sum(4, 5) : object 'sUm' not found

这是有效的,因为baseenv()指向&#34; base&#34;空的环境。但请注意,您无法使用此方法访问其他功能

myfun<-function(x,y) {x+y}
sum <- function(x,y){sum = myfun(x+y); return(sUm)}

environment(sum)<-baseenv()
sum(4,5)
# Error in sum(4, 5) : could not find function "myfun"

因为在诸如R之类的函数语言中,函数只是常规变量,它们也在定义它们的环境中作用域,并且在基础环境中不可用。

您需要手动更改您编写的每个函数的环境。同样,没有办法更改此默认行为,因为包中定义的许多基本R函数和函数都依赖于此行为。

答案 2 :(得分:3)

使用get是一种方式:

sUm <- 10
sum <- function(x,y){
  sum <- x+y
  #with inherits = FALSE below the variable is only searched 
  #in the specified environment in the envir argument below
  get('sUm', envir = environment(), inherits=FALSE) 
}

输出:

> sum(1,6)
Error in get("sUm", envir = environment(), inherits = FALSE) : 
  object 'sUm' not found

在get函数中拥有正确的sum仍然只能在函数的环境中查找变量,这意味着如果有两个变量,一个在函数内部,一个在全局环境中具有相同的名称,该函数总是在函数环境中查找变量,而不是在全局环境中查找:

sum <- 10
sum2 <- function(x,y){
  sum <- x+y
  get('sum', envir = environment(), inherits=FALSE) 
}

> sum2(1,7)
[1] 8

答案 3 :(得分:3)

您可以检查变量的名称是否出现在全局变量列表中。请注意,如果所讨论的全局变量与函数的参数具有相同的名称,则这是不完美的。

if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv))
    stop("Do not use a global variable!")

stop()函数将暂停执行该函数并显示给定的错误消息。

答案 4 :(得分:2)

另一种方式(或风格)是将所有全局变量保存在特殊环境中:

with( globals <- new.env(), {
  # here define all "global variables"  
  sUm <- 10
  mEan <- 5
})

# or add a variable by using $
globals$another_one <- 42

然后该功能无法获得它们:

sum <- function(x,y){
  sum = x+y
  return(sUm)
}

sum(1,2)
# Error in sum(1, 2) : object 'sUm' not found

但你可以随时使用全局变量$:

globals$sUm
[1] 10

要管理规则,您可以检查globals之外是否存在任何全局变量(函数除外):

setdiff(ls(), union(lsf.str(), "globals")))