2009-07-23 6 views
30

J'écris souvent des fonctions qui ont besoin de voir d'autres objets dans mon environnement. Par exemple:Écrire des fonctions dans R, en gardant à l'esprit la portée

> 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 

Comme prévu, ces deux fonctions sont identiques parce que fn2 peut « voir » a et b quand il exécute. Mais chaque fois que je commence à tirer parti de cela, dans les 30 minutes environ, je finis par appeler la fonction sans l'une des variables nécessaires (par exemple, a ou b). Si je n'en profite pas, j'ai l'impression de passer inutilement des objets.

Est-il préférable d'être explicite sur ce qu'une fonction nécessite? Ou devrait-il être pris en charge via des commentaires en ligne ou d'autres documents de la fonction? Y a-t-il un meilleur moyen?

Répondre

36

Si je sais que je vais avoir besoin d'une fonction paramétrée par certaines valeurs et appelé à plusieurs reprises, j'éviter GLOBALS en utilisant une fermeture:

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 

Cela évite soigneusement référencer les variables globales, en utilisant plutôt le englobante environnement de la fonction pour a et b. La modification des globales a et b n'entraîne pas d'effets secondaires involontaires lorsque les instances fn2 sont appelées.

3

Le problème se produit-il lorsque vous utilisez simplement une variable globale dans une fonction ou lorsque vous essayez d'affecter la variable? Si c'est le dernier, je suppose que c'est parce que vous n'utilisez pas <<- comme une affectation dans la fonction. Et tout en utilisant <<- semble être le côté obscur 1 il peut très bien fonctionner pour vos fins. Si c'est la première, la fonction masque probablement la variable globale.

Nommer des variables globales d'une manière qu'il serait difficile de les masquer localement pourrait aider. par exemple: global.pimultiples <- 1:4*pi

8

Il y a une raison pour laquelle certaines langues n'autorisent pas les variables globales: elles peuvent facilement mener au code cassé. Les règles de portée de R vous permettent d'écrire du code paresseux - le fait de laisser les fonctions utiliser des variables dans d'autres environnements peut vous épargner un peu de frappe, et c'est parfait pour jouer dans des cas simples. Si vous faites quelque chose de compliqué, cependant, je vous recommande de passer une fonction à toutes les variables dont il a besoin (ou tout au moins, d'avoir une vérification approfondie en place pour avoir une solution de repli dans le cas où les variables don n'existe pas).

Dans l'exemple ci-dessus:

La meilleure pratique consiste à utiliser FN1.

Sinon, essayez quelque chose comme

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

Utilisation des variables globales est en général déconseillée dans la plupart des langues, et R ne fait pas exception. Très souvent, les fonctions courtes utilisent des noms de variables courts et génériques, qui peuvent être renseignés dans l'environnement global. Il est plus sûr a) d'inclure toutes les variables dans la définition de la fonction b) et non pour attribuer des valeurs par défaut. Par exemple, écrivez f = fonction (a, b), plutôt f = fonction (a = 0, b = NA).

Questions connexes