2009-07-23 20 views
30

A menudo escribo funciones que necesitan ver otros objetos en mi entorno. Por ejemplo:Escribir funciones en R, teniendo en cuenta el alcance

> 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 

Como era de esperar, estas dos funciones son idénticas porque fn2 puede "ver" A y B cuando se ejecuta. Pero cada vez que empiezo a aprovechar esto, en aproximadamente 30 minutos termino llamando a la función sin una de las variables necesarias (por ejemplo, aob). Si no me aprovecho de esto, entonces siento que estoy pasando innecesariamente por los objetos.

¿Es mejor ser explícito sobre lo que requiere una función? ¿O debería hacerse cargo de esto a través de comentarios en línea u otra documentación de la función? ¿Hay una mejor manera?

Respuesta

36

Si sé que voy a necesitar una función parametrizada por algunos valores y pedido en repetidas ocasiones, evito globales mediante el uso de un cierre:

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 

Esto evita cuidadosamente hacer referencia a variables globales, en lugar de utilizar la envolvente entorno de la función para a y b. La modificación de globals ayb no produce efectos secundarios no deseados cuando se invocan instancias de fn2.

3

¿Se produce el problema cuando solo está utilizando una variable global en una función o cuando intenta asignar la variable? Si es el último, sospecho que es porque no está usando <<- como una tarea dentro de la función. Y mientras usa <<- parece ser el lado oscuro 1, puede funcionar para sus propósitos. Si es el primero, la función probablemente enmascara la variable global.

Nombrar variables globales de una manera en la que sería difícil enmascararlas localmente podría ayudar. e.g .: global.pimultiples <- 1:4*pi

8

Hay una razón por la que algunos idiomas no permiten variables globales: pueden conducir fácilmente a código roto.

Las reglas de scoping en R le permiten escribir código de forma perezosa: dejar que las funciones usen variables en otros entornos puede ahorrarle algo de mecanografía, y es genial para jugar en casos simples.

Sin embargo, si está haciendo algo remotamente complicado, le recomiendo que pase una función con todas las variables que necesita (o al menos, realice una minuciosa comprobación de cordura para tener un respaldo en caso de que las variables 't existe).

En el ejemplo anterior:

La mejor práctica es utilizar FN1.

Alternativamente, intentar algo así como

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 
    } 
0

uso de variables globales no se recomienda en general en la mayoría de los idiomas, y R no es una excepción. Muy a menudo, la función corta usa nombres de variables cortas y genéricas, que pueden ser pobladas en el entorno global. Es más seguro a) incluir todas las variables en la definición de la función b) no para asignar valores predeterminados. Por ejemplo, escriba f = función (a, b), más bien f = función (a = 0, b = NA).

Cuestiones relacionadas