在R中编写函数,记住范围

时间:2009-07-23 03:58:11

标签: r scope

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

> 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)。如果我没有利用这一点,那么我觉得我不必要地绕过物体。

明确一个函数需要什么更好?或者应该通过内联注释或函数的其他文档来处理?还有更好的方法吗?

4 个答案:

答案 0 :(得分:36)

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

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不会导致意外的副作用。

答案 1 :(得分:8)

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

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
   }

答案 2 :(得分:3)

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

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

答案 3 :(得分:0)

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