【问题标题】:R scoping: disallow global variables in functionR范围:禁止函数中的全局变量
【发布时间】:2015-03-10 18:04:38
【问题描述】:

如果在R 函数中使用了全局变量,有什么方法可以引发警告(并失败..)?我认为这样可以节省很多,并且可以防止意外行为...例如

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

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

【问题讨论】:

标签: r scope global


【解决方案1】:

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

为确保您的函数在不应该使用的情况下不使用全局变量,请使用 codetools 包。

library(codetools)

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

checkUsage(f)

这将打印消息:

&lt;anonymous&gt; local variable ‘sum’ assigned but may not be used (:1)

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

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

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

这表明全局变量 sUm 在可能不应该使用的情况下在 f() 内部使用。

【讨论】:

  • 这个不错!检查全局变量是否在函数中被错误使用的简单方法。不知道那个包。谢谢!
  • @Jonas:很高兴我能帮上忙。
【解决方案2】:

没有办法永久改变变量的解析方式,因为这会破坏很多功能。你不喜欢的行为在很多情况下其实很有用。

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

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

这是有效的,因为baseenv() 指向空的“基础”环境。但是请注意,您无法使用此方法访问其他功能

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 函数和函数都依赖此行为。

【讨论】:

  • 有一个功能制作功能可以为您完成这项工作吗?
  • 好吧,你仍然有一个问题,那就是在 R 中区分“变量”和“函数”并不容易。为了有用,你可能需要访问所有命名空间中的函数。但有时您可能希望编写返回其他函数的函数。对我来说,合适的包装器是什么样的并不明显。
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

    使用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
    

    【讨论】:

      【解决方案5】:

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

      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$ 一起使用:

      globals$sUm
      [1] 10
      

      要管理学科,可以检查globals之外是否有任何全局变量(函数除外):

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-13
        • 1970-01-01
        • 2015-03-22
        • 2012-04-29
        • 2017-02-17
        • 1970-01-01
        相关资源
        最近更新 更多