Biến toàn cục và cục bộ trong R


126

Tôi là người mới chơi R và tôi khá bối rối với việc sử dụng các biến cục bộ và toàn cầu trong R.

Tôi đọc một số bài đăng trên internet nói rằng nếu tôi sử dụng =hoặc <-tôi sẽ chỉ định biến trong môi trường hiện tại và <<-tôi có thể truy cập một biến toàn cục khi ở trong hàm.

Tuy nhiên, như tôi nhớ trong C ++, các biến cục bộ phát sinh bất cứ khi nào bạn khai báo một biến trong ngoặc {}, vì vậy tôi tự hỏi liệu điều này có giống với R không? Hoặc là chỉ cho các hàm trong R mà chúng ta có khái niệm về các biến cục bộ.

Tôi đã làm một thí nghiệm nhỏ, dường như gợi ý rằng chỉ dấu ngoặc là không đủ, tôi có nhận được gì sai không?

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

Một số mã để chạy ngoài những câu trả lời: globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env...
isomorphismes

@isomorism , Error: could not find function "%>%". Đó có phải là một hình thức chuyển nhượng khác?
Aaron McDaid

1
Chuỗi liên quan trên trợ giúp R: Toán tử "<< -" nghĩa là gì? .
Henrik

1
@AaronMcDaid Xin chào, xin lỗi vì đã không trả lời sớm hơn! Đó là từ require(magrittr). Đó là cách áp dụng các hàm ở bên phải ( x | f1 | f2 | f3) thay vì ở bên trái ( f3( f2( f1( x ) ) )).
đẳng cấu

Câu trả lời:


153

Các biến được khai báo bên trong một hàm là cục bộ của hàm đó. Ví dụ:

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

đưa ra lỗi sau : Error: object 'bar' not found.

Nếu bạn muốn tạo barmột biến toàn cục, bạn nên làm:

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

Trong trường hợp barnày có thể truy cập từ bên ngoài chức năng.

Tuy nhiên, không giống như C, C ++ hoặc nhiều ngôn ngữ khác, dấu ngoặc không xác định phạm vi của các biến. Chẳng hạn, trong đoạn mã sau:

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

yvẫn có thể truy cập sau khi if-elsetuyên bố.

Như bạn cũng nói, bạn cũng có thể tạo các môi trường lồng nhau. Bạn có thể xem hai liên kết này để hiểu cách sử dụng chúng:

  1. http://stat.ethz.ch/R-manual/R-devel/l Library / base / html / en môi.html
  2. http://stat.ethz.ch/R-manual/R-devel/l Library / base / html / get.html

Ở đây bạn có một ví dụ nhỏ:

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

<- không phân công trong môi trường hiện tại.

Khi bạn ở trong hàm R sẽ tạo một môi trường mới cho bạn. Theo mặc định, nó bao gồm mọi thứ từ môi trường mà nó được tạo để bạn có thể sử dụng các biến đó nhưng mọi thứ mới bạn tạo sẽ không được ghi vào môi trường toàn cầu.

Trong hầu hết các trường hợp <<-sẽ gán cho các biến đã có trong môi trường toàn cầu hoặc tạo một biến trong môi trường toàn cầu ngay cả khi bạn đang ở trong một hàm. Tuy nhiên, nó không hoàn toàn đơn giản như vậy. Những gì nó làm là kiểm tra môi trường cha cho một biến có tên quan tâm. Nếu nó không tìm thấy nó trong môi trường cha mẹ của bạn, nó sẽ chuyển đến cha mẹ của môi trường cha mẹ (tại thời điểm hàm được tạo) và nhìn vào đó. Nó tiếp tục hướng lên môi trường toàn cầu và nếu không tìm thấy trong môi trường toàn cầu, nó sẽ gán biến trong môi trường toàn cầu.

Điều này có thể minh họa những gì đang xảy ra.

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"

Lần đầu tiên chúng tôi in thanh mà chúng tôi chưa gọi foonên nó vẫn mang tính toàn cầu - điều này có ý nghĩa. Lần thứ hai chúng tôi in nó bên trong footrước khi gọi bazđể giá trị "trong foo" có ý nghĩa. Sau đây là nơi chúng ta thấy những gì <<-đang thực sự làm. Giá trị tiếp theo được in là "in baz - before << -" mặc dù câu lệnh in xuất hiện sau <<-. Điều này là do <<-không nhìn vào môi trường hiện tại (trừ khi bạn ở trong môi trường toàn cầu trong trường hợp đó <<-hoạt động như thế nào <-). Vì vậy, bên trong bazgiá trị của thanh vẫn là "in baz - trước << -". Khi chúng ta gọi bazbản sao của thanh bên trong foođược thay đổi thành "in baz" nhưng như chúng ta có thể thấy toàn cầu barlà không thay đổi.barđược định nghĩa bên trong foolà trong môi trường phụ huynh khi chúng tôi tạo ra bazvì vậy đây là bản sao đầu tiên của bar<<-nhìn thấy và do đó sao chép nó gán cho. Vì vậy, <<-không chỉ trực tiếp giao cho môi trường toàn cầu.

<<-là khó khăn và tôi không khuyên bạn nên sử dụng nó nếu bạn có thể tránh nó. Nếu bạn thực sự muốn gán cho môi trường toàn cầu, bạn có thể sử dụng hàm gán và nói rõ rằng bạn muốn gán toàn cục.

Bây giờ tôi thay đổi <<-câu lệnh gán và chúng ta có thể thấy tác dụng nào có:

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"

Vì vậy, cả hai lần chúng tôi in thanh bên trong foogiá trị là "trong foo" ngay cả sau khi gọi baz. Điều này là do assignthậm chí không bao giờ xem xét bản sao barbên trong của foo bởi vì chúng tôi đã nói với nó chính xác nơi để tìm. Tuy nhiên, lần này giá trị của thanh trong môi trường toàn cầu đã thay đổi vì chúng tôi được chỉ định rõ ràng ở đó.

Bây giờ bạn cũng đã hỏi về việc tạo các biến cục bộ và bạn có thể thực hiện điều đó khá dễ dàng mà không cần tạo hàm ... Chúng ta chỉ cần sử dụng localhàm.

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

2

Một chút nữa dọc theo cùng một dòng

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

sẽ in "1"

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

Sẽ in "20"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.