Variables globales et locales dans R


126

Je suis un débutant pour R, et je suis assez confus avec l'utilisation des variables locales et globales dans R.

J'ai lu quelques articles sur Internet qui disent si j'utilise =ou <-si j'attribue la variable dans l'environnement actuel, et avec <<-je peux accéder à une variable globale à l'intérieur d'une fonction.

Cependant, comme je me souviens en C ++, les variables locales surviennent chaque fois que vous déclarez une variable entre crochets {}, donc je me demande si c'est la même chose pour R? Ou est-ce juste pour les fonctions dans R que nous avons le concept de variables locales.

J'ai fait une petite expérience, qui semble suggérer que seules les parenthèses ne suffisent pas, est-ce que je me trompe?

{
   x=matrix(1:10,2,5)
}
print(x[2,2])
[1] 4

Du code à exécuter en plus de ces réponses: globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env,…
isomorphismes

@isomorphismes, Error: could not find function "%>%". Est-ce une autre forme de cession?
Aaron McDaid

1
Thread pertinent sur R-help: Que signifie l'opérateur "<< -"? .
Henrik

1
@AaronMcDaid Salut, désolé de ne pas avoir répondu plus tôt! C'est de require(magrittr). C'est une façon d'appliquer des fonctions à droite ( x | f1 | f2 | f3) plutôt qu'à gauche ( f3( f2( f1( x ) ) )).
isomorphismes

Réponses:


153

Les variables déclarées à l'intérieur d'une fonction sont locales à cette fonction. Par exemple:

foo <- function() {
    bar <- 1
}
foo()
bar

donne l'erreur suivante: Error: object 'bar' not found.

Si vous souhaitez créer barune variable globale, vous devez faire:

foo <- function() {
    bar <<- 1
}
foo()
bar

Dans ce cas barest accessible de l'extérieur de la fonction.

Cependant, contrairement au C, C ++ ou à de nombreux autres langages, les crochets ne déterminent pas la portée des variables. Par exemple, dans l'extrait de code suivant:

if (x > 10) {
    y <- 0
}
else {
    y <- 1
}

yreste accessible après la if-elsedéclaration.

Comme vous le dites, vous pouvez également créer des environnements imbriqués. Vous pouvez consulter ces deux liens pour comprendre comment les utiliser:

  1. http://stat.ethz.ch/R-manual/R-devel/library/base/html/environment.html
  2. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

Voici un petit exemple:

test.env <- new.env()

assign('var', 100, envir=test.env)
# or simply
test.env$var <- 100

get('var') # var cannot be found since it is not defined in this environment
get('var', envir=test.env) # now it can be found

136

<- fait une affectation dans l'environnement actuel.

Lorsque vous êtes à l'intérieur d'une fonction, R crée un nouvel environnement pour vous. Par défaut, il inclut tout ce qui concerne l'environnement dans lequel il a été créé afin que vous puissiez également utiliser ces variables, mais tout ce que vous créez ne sera pas écrit dans l'environnement global.

Dans la plupart des cas <<-, affectera des variables déjà dans l'environnement global ou créera une variable dans l'environnement global même si vous êtes à l'intérieur d'une fonction. Cependant, ce n'est pas aussi simple que cela. Il vérifie dans l'environnement parent une variable avec le nom qui vous intéresse. S'il ne le trouve pas dans votre environnement parent, il va au parent de l'environnement parent (au moment où la fonction a été créée) et y regarde. Il continue vers le haut dans l'environnement global et s'il n'est pas trouvé dans l'environnement global, il affectera la variable dans l'environnement global.

Cela pourrait illustrer ce qui se passe.

bar <- "global"
foo <- function(){
    bar <- "in foo"
    baz <- function(){
        bar <- "in baz - before <<-"
        bar <<- "in baz - after <<-"
        print(bar)
    }
    print(bar)
    baz()
    print(bar)
}
> bar
[1] "global"
> foo()
[1] "in foo"
[1] "in baz - before <<-"
[1] "in baz - after <<-"
> bar
[1] "global"

La première fois que nous imprimons la barre, nous n'avons pas fooencore appelé , donc elle devrait toujours être globale - cela a du sens. La deuxième fois que nous imprimons, il est à l'intérieur de fooavant d'appeler, bazdonc la valeur "in foo" a du sens. Voici où nous voyons ce qui <<-se passe réellement. La valeur suivante imprimée est "in baz - before << -" même si l'instruction print vient après le <<-. C'est parce <<-que ne regarde pas dans l'environnement actuel (sauf si vous êtes dans l'environnement global, auquel cas <<-agit comme <-). Donc à l'intérieur de bazla valeur de bar reste comme "in baz - before << -". Une fois que nous appelons bazla copie de bar à l'intérieur de foodevient "in baz", mais comme nous pouvons le voir, le global barest inchangé.barqui est défini à l'intérieur de fooest dans l'environnement parent lorsque nous avons créé baz, c'est donc la première copie de ce barqui <<-voit et donc la copie à laquelle il assigne. Il <<-ne s'agit donc pas simplement d'assigner directement à l'environnement mondial.

<<-est délicat et je ne recommanderais pas de l'utiliser si vous pouvez l'éviter. Si vous voulez vraiment assigner à l'environnement global, vous pouvez utiliser la fonction assign et lui dire explicitement que vous voulez assigner globalement.

Maintenant, je change le <<-en une instruction assign et nous pouvons voir quel effet cela a:

bar <- "global"
foo <- function(){
    bar <- "in foo"   
    baz <- function(){
        assign("bar", "in baz", envir = .GlobalEnv)
    }
    print(bar)
    baz()
    print(bar)
}
bar
#[1] "global"
foo()
#[1] "in foo"
#[1] "in foo"
bar
#[1] "in baz"

Ainsi, les deux fois que nous imprimons la barre à l'intérieur de foola valeur est "in foo" même après l'appel baz. C'est parce que nous assignn'avons même jamais considéré la copie de barinside of foo parce que nous lui avons dit exactement où chercher. Cependant, cette fois, la valeur de bar dans l'environnement global a été modifiée parce que nous l'avons explicitement assignée.

Maintenant, vous avez également posé des questions sur la création de variables locales et vous pouvez le faire assez facilement également sans créer de fonction ... Nous avons juste besoin d'utiliser la localfonction.

bar <- "global"
# local will create a new environment for us to play in
local({
    bar <- "local"
    print(bar)
})
#[1] "local"
bar
#[1] "global"

2

Un peu plus dans le même sens

attrs <- {}

attrs.a <- 1

f <- function(d) {
    attrs.a <- d
}

f(20)
print(attrs.a)

affichera "1"

attrs <- {}

attrs.a <- 1

f <- function(d) {
   attrs.a <<- d
}

f(20)
print(attrs.a)

Imprime "20"

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.