2010-04-15 8 views
3

Suite aux discussions récentes ici (par exemple, 1, 2), j'utilise maintenant des environnements dans certains de mes codes. Ma question est, comment puis-je créer des fonctions qui modifient les environnements en fonction de ses arguments? Par exemple:Utilisation des fonctions et des environnements

y <- new.env() 
with(y, x <- 1) 
f <- function(env,z) { 
    with(env, x+z) 
} 
f(y,z=1) 

lancers francs

Error in eval(expr, envir, enclos) : object 'z' not found 

J'utilise des environnements pour maintenir simultanément deux séries de simulations à part (sans refactorisation mon code, que j'ai écrit pour un seul ensemble d'expériences).

+2

Y at-il une raison d'utiliser 'with'? Sinon, vous pouvez utiliser 'env $ x + z'. – Marek

+0

Dans ma fonction, je référence beaucoup d'objets dans l'environnement, d'où le 'avec '. Mais c'est une bonne solution et je pourrais l'utiliser. –

+1

Qu'essayez-vous de faire? Je soupçonne que tout ce que vous essayez d'accomplir sera mieux fait sans référence explicite aux environnements. Dans les paquets de plus de 15 que j'ai écrits et les nombreuses analyses de données que j'ai faites, je n'ai eu à utiliser explicitement les environnements qu'une poignée de fois. – hadley

Répondre

7

La solution la plus simple est d'utiliser l'environnement lors du référencement de l'objet:

y <- new.env() 
y$x <- 1 
f <- function(env,z) { 
    env$x+z 
} 
f(y,z=1) 

Vous devrez attribuer z à votre environnement ainsi.

y <- new.env() 
with(y, x <- 1) 
f <- function(env,z) { 
    assign("z", z, envir=env) 
    with(env, x+z) 
} 
f(y,z=1) 

Une autre option serait de attach votre environnement afin que les variables peuvent maintenant être utilisées directement.

y <- new.env() 
with(y, x <- 1) 
f <- function(env,z) { 
    attach(env) 
    y <- x + z 
    detach(env) 
    y 
} 
f(y,z=1) 

Cette dernière solution est puissante, car cela signifie que vous pouvez utiliser un objet de tout environnement attaché au sein de votre nouvel environnement, mais cela signifie aussi que vous devez faire très attention à ce qui a été attribué à l'échelle mondiale.

Modifier:

Ce qui est intéressant, et je ne comprends pas tout à fait le comportement (à savoir pourquoi z est pas dans le cadre de l'appel with). Il a quelque chose à voir avec la création de l'environnement à l'origine qui est à l'origine d'être en dehors du champ d'application de la fonction, car cette version fonctionne:

f <- function(z) { 
    y <- new.env() 
    with(y, x <- 1) 
    with(y, x+z) 
} 
f(y,z=1) 
+0

Merci. J'utilisais la solution avec attach. Mais quand la fonction rencontre une erreur avant de se détacher, j'obtiens les problèmes d'attachement typiques. Affecter des travaux. Je préfère être temporaire (comme dans une fonction régulière), cependant. Je ne peux pas l'avoir des deux côtés, je suppose. –

+0

Voir ma réponse mise à jour. En outre, si vous rencontrez un problème, enveloppez tout dans un bloc try ou tryCatch, et détachez-le malgré tout. – Shane

+1

Quelle est la raison pour laquelle z n'est pas dans le chemin de recherche du code OP? De la docs pour with(): "L'environnement a l'environnement de l'appelant comme parent." En outre, avec (y, x + z) semble fonctionner au plus haut niveau. Je suis un peu perplexe par la raison pour laquelle cela échoue dans l'appel de la fonction. –

3

Il vous suffit de faire un changement pour rendre votre travail par exemple - redéfinir votre fonction à utiliser substitute() pour « fixer » les valeurs souhaitées dans le cadre de f():

f <- function(env,z) { 
    eval(substitute(x+z,list(z=z)), env) 
} 

Cela peut rapidement se trouble d'autant plus que vous pouvez même inclure des instructions d'affectation dans substitute() (par exemple, remplacer x+z avec y <- x+z, pas que cela est tout à fait pertinent ici), mais ce choix peut être fait par le développeur ...

De plus, vous pouvez remplacer list(z=z) dans l'expression de substitution ci-dessus avec environment() (par exemple, substitute(x+z,environment())) aussi longtemps que vous n » • Vous avez des noms de variables contradictoires entre ceux passés à f() et ceux résidant dans votre «env», mais vous ne voulez peut-être pas aller trop loin.

Editer: Voici deux autres moyens, dont le premier est uniquement destiné à montrer la flexibilité dans la manipulation des environnements et le second est plus raisonnable à utiliser réellement.

1) modifier l'environnement d'enceinte de « env » (mais changer de nouveau à la valeur initiale avant la fonction sortant):

f <- function(env,z) { 
    e <- environment(env) 
    environment(env) <- environment() 
    output <- with(env,x+z) 
    environment(env) <- e 
    output 
} 

2) l'évaluation de la Force de « z » dans l'environnement actuel de la fonction (en utilisant environment()) plutôt que de le laisser rester une variable libre après évaluation de l'expression, x+z, dans 'env'.

f <- function(env,z) { 
    with(environment(),with(env,x+z)) 
} 

En fonction de votre commande de résolution souhaitée, en cas d'associations valeur de symbole en conflit - par exemple, si vous avez « x » défini à la fois l'environnement de la fonction et de l'environnement que vous avez créé, « y » (dont la valeur de 'x' voulez-vous supposer?) - vous pouvez définir le corps de la fonction à with(env,with(environment(),x+z)).

1
y <- new.env() 
with(y, x <- 1) 
f <- function(env,z) { 
    with(env, x+z) 
} 
f(y,z=1) 

esprit les parenthèses :) Les éléments suivants fonctionnent:

with(env, x)+z 
Questions connexes