Zmienne globalne i lokalne w R.


126

Jestem nowicjuszem w R i jestem dość zdezorientowany użyciem zmiennych lokalnych i globalnych w R.

Czytałem kilka postów w Internecie, które mówią, czy używam =lub <-przypiszę zmienną w bieżącym środowisku, a dzięki temu <<-mogę uzyskać dostęp do zmiennej globalnej, gdy jestem wewnątrz funkcji.

Jednak, jak pamiętam w C ++, zmienne lokalne pojawiają się za każdym razem, gdy deklarujesz zmienną w nawiasach {}, więc zastanawiam się, czy to jest to samo dla R? A może tylko dla funkcji w R mamy pojęcie zmiennych lokalnych.

Zrobiłem mały eksperyment, który wydaje się sugerować, że same nawiasy to za mało, czy coś mi się nie podoba?

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

Jakiś kod do uruchomienia oprócz tych odpowiedzi: globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env,…
izomorfizm

@isomorphismes, Error: could not find function "%>%". Czy to inna forma zlecenia?
Aaron McDaid

1
Odpowiedni wątek w pomocy R: Co oznacza operator „<< -”? .
Henrik

1
@AaronMcDaid Cześć, przepraszam, że nie odpowiadam wcześniej! To jest z require(magrittr). Jest to sposób stosowania funkcji po prawej stronie ( x | f1 | f2 | f3) zamiast po lewej stronie ( f3( f2( f1( x ) ) )).
izomorfizmy

Odpowiedzi:


153

Zmienne zadeklarowane wewnątrz funkcji są lokalne dla tej funkcji. Na przykład:

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

wydaje następujący błąd: Error: object 'bar' not found.

Jeśli chcesz stworzyć barzmienną globalną, powinieneś zrobić:

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

W tym przypadku barjest dostępny z zewnątrz funkcji.

Jednak w przeciwieństwie do C, C ++ i wielu innych języków, nawiasy nie określają zakresu zmiennych. Na przykład w następującym fragmencie kodu:

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

ypozostaje dostępny po if-elseoświadczeniu.

Jak dobrze powiesz, możesz także tworzyć środowiska zagnieżdżone. Możesz rzucić okiem na te dwa linki, aby zrozumieć, jak ich używać:

  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

Tutaj masz mały przykład:

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

<- wykonuje przypisanie w obecnym środowisku.

Kiedy jesteś wewnątrz funkcji, R tworzy dla ciebie nowe środowisko. Domyślnie zawiera wszystko ze środowiska, w którym został utworzony, więc możesz również użyć tych zmiennych, ale wszystko, co stworzysz, nie zostanie zapisane w środowisku globalnym.

W większości przypadków <<-przypisze zmienne już w środowisku globalnym lub utworzy zmienną w środowisku globalnym, nawet jeśli jesteś wewnątrz funkcji. Jednak nie jest to takie proste. To, co robi, to sprawdzenie środowiska nadrzędnego pod kątem zmiennej o nazwie, która nas interesuje. Jeśli nie znajdzie go w twoim środowisku nadrzędnym, przechodzi do środowiska nadrzędnego środowiska nadrzędnego (w momencie tworzenia funkcji) i tam szuka. Kontynuuje w górę do środowiska globalnego i jeśli nie zostanie znaleziony w środowisku globalnym, przypisze zmienną w środowisku globalnym.

To może zilustrować, co się dzieje.

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"

Gdy po raz pierwszy drukujemy pasek, którego jeszcze nie foowywołaliśmy, powinien nadal być globalny - to ma sens. Za drugim razem, gdy drukujemy, znajduje się w środku fooprzed wywołaniem, bazwięc wartość „in foo” ma sens. Poniżej znajduje się, gdzie widzimy, co <<-faktycznie robi. Następna wypisywana wartość to "in baz - przed << -", mimo że instrukcja print występuje po <<-. Dzieje się tak, ponieważ <<-nie wygląda w obecnym środowisku (chyba że jesteś w środowisku globalnym, w którym to przypadku <<-zachowuje się tak <-). Zatem wewnątrz bazwartości bar pozostaje „in baz - przed << -”. Kiedy już wywołamy bazkopię wewnątrz bara, foozostanie zmieniona na "in baz", ale jak widzimy, globalny barpozostaje niezmieniony.barktóra jest zdefiniowana wewnątrz programu, fooznajduje się w środowisku nadrzędnym podczas tworzenia, bazwięc jest to pierwsza kopia tego, barktóra <<-widzi, a tym samym kopia, do której przypisuje. Nie <<-jest to więc tylko bezpośrednie przypisywanie do środowiska globalnego.

<<-jest trudna i nie polecałbym jej używać, jeśli możesz jej uniknąć. Jeśli naprawdę chcesz przypisać do środowiska globalnego, możesz użyć funkcji przypisania i wyraźnie powiedzieć, że chcesz przypisać globalnie.

Teraz zmieniam instrukcję <<-na przypisaną i możemy zobaczyć, jaki to ma skutek:

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"

Więc za każdym razem wypisujemy bar wewnątrz foowartości "in foo" nawet po wywołaniu baz. Dzieje się tak, ponieważ assignnigdy nawet nie rozważaliśmy kopii barwnętrza foo, ponieważ powiedzieliśmy mu dokładnie, gdzie szukać. Jednak tym razem wartość bar w środowisku globalnym została zmieniona, ponieważ wyraźnie tam przypisaliśmy.

Teraz zapytałeś również o tworzenie zmiennych lokalnych i możesz to zrobić dość łatwo bez tworzenia funkcji ... Musimy tylko użyć localfunkcji.

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

2

Nieco bardziej w tym samym kierunku

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

wypisze "1"

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

Wydrukuje „20”

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.