【问题标题】:Writing functions in R, keeping scoping in mind在 R 中编写函数,牢记范围
【发布时间】:2010-11-13 06:17:11
【问题描述】:

我经常编写需要查看环境中其他对象的函数。例如:

> a <- 3
> b <- 3
> x <- 1:5
> fn1 <- function(x,a,b) a+b+x
> fn2 <- function(x) a+b+x
> fn1(x,a,b)
[1]  7  8  9 10 11
> fn2(x)
[1]  7  8  9 10 11

正如预期的那样,这两个函数是相同的,因为fn2 在执行时可以“看到” a 和 b。但是每当我开始利用这一点时,在大约 30 分钟内,我最终会在没有必要变量之一(例如 a 或 b)的情况下调用该函数。如果我不利用这一点,我会觉得我在不必要地传递对象。

明确说明函数需要什么会更好吗?还是应该通过内联 cmets 或函数的其他文档来解决这个问题?有没有更好的办法?

【问题讨论】:

    标签: r scope


    【解决方案1】:

    当您只是在函数中使用全局变量或尝试分配变量时是否会出现问题?如果是后者,我怀疑这是因为您没有使用 &lt;&lt;- 作为函数中的赋值。虽然使用&lt;&lt;- 似乎是黑暗的一面1 它可能非常适合您的目的。如果是前者,则该函数可能正在屏蔽全局变量。

    以难以在本地掩盖它们的方式命名全局变量可能会有所帮助。例如:global.pimultiples &lt;- 1:4*pi

    【讨论】:

      【解决方案2】:

      有些语言不允许使用全局变量是有原因的:它们很容易导致代码损坏。

      R 中的作用域规则允许您以懒惰的方式编写代码 - 让函数在其他环境中使用变量可以为您节省一些输入,并且非常适合在简单的情况下玩耍。

      但是,如果您正在做任何远程复杂的事情,那么我建议您将它需要的所有变量传递给一个函数(或者至少,进行一些彻底的完整性检查,以便在变量没有的情况下进行后备)不存在)。

      在上面的例子中:

      最佳做法是使用 fn1。

      或者,尝试类似的方法

       fn3 <- function(x)
         {
            if(!exists("a", envir=.GlobalEnv))
            {
               warning("Variable 'a' does not exist in the global environment")
               a <- 1
            }
      
            if(!exists("b", envir=.GlobalEnv))
            {
               warning("Variable 'b' does not exist in the global environment")
               b <- 2
            }
      
            x + a + b
         }
      

      【讨论】:

        【解决方案3】:

        在大多数语言中通常不鼓励使用全局变量,R 也不例外。短函数通常使用短的通用变量名,可以在全局环境中填充。 a) 在函数定义中包含所有变量 b) not 分配默认值是最安全的。例如,写 f=function(a,b),而不是 f=function(a=0,b=NA)。

        【讨论】:

          【解决方案4】:

          如果我知道我需要一个由某些值参数化并重复调用的函数,我会通过使用闭包来避免全局变量:

          make.fn2 <- function(a, b) {
              fn2 <- function(x) {
                  return( x + a + b )
              }
              return( fn2 )
          }
          
          a <- 2; b <- 3
          fn2.1 <- make.fn2(a, b)
          fn2.1(3)    # 8
          fn2.1(4)    # 9
          
          a <- 4
          fn2.2 <- make.fn2(a, b)
          fn2.2(3)    # 10
          fn2.1(3)    # 8
          

          这巧妙地避免了引用全局变量,而是为 a 和 b 使用函数的封闭环境。调用 fn2 实例时,修改全局变量 a 和 b 不会导致意外的副作用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-11-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-28
            • 1970-01-01
            • 2021-03-06
            相关资源
            最近更新 更多