R中的全局变量和局部变量

时间:2022-06-03 09:08:14

I am a newbie for R, and I am quite confused with the usage of local and global variables in R.

我是R的新手,我对R中的局部变量和全局变量的用法很困惑。

I read some posts on the internet that say if I use = or <- I will assign the variable in the current environment, and with <<- I can access a global variable when inside a function.

我在因特网上读到一些文章,说如果我使用=或<-我将在当前环境中分配变量,而使用<<- I可以在函数内部访问全局变量。

However, as I remember in C++ local variables arise whenever you declare a variable inside brackets {}, so I'm wondering if this is the same for R? Or is it just for functions in R that we have the concept of local variables.

但是,正如我在c++中所记得的,每当您在括号{}中声明一个变量时,就会出现局部变量,所以我想知道这对R是否相同?或者它仅仅是关于R中的函数我们有局部变量的概念。

I did a little experiment, which seems to suggest that only brackets are not enough, am I getting anything wrong?

我做了一个小实验,似乎表明只有括号是不够的,我做错了什么吗?

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

3 个解决方案

#1


113  

Variables declared inside a function are local to that function. For instance:

函数中声明的变量是该函数的局部变量。例如:

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

gives the following error: Error: object 'bar' not found.

给出以下错误:错误:未找到对象'bar'。

If you want to make bar a global variable, you should do:

如果你想让bar成为一个全局变量,你应该这样做:

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

In this case bar is accessible from outside the function.

在这种情况下,bar可以从函数外部访问。

However, unlike C, C++ or many other languages, brackets do not determine the scope of variables. For instance, in the following code snippet:

但是,与C、c++或其他许多语言不同,括号不能确定变量的范围。例如,在下面的代码片段中:

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

y remains accessible after the if-else statement.

在if-else语句之后,y仍然是可访问的。

As you well say, you can also create nested environments. You can have a look at these two links for understanding how to use them:

正如您所说,您还可以创建嵌套环境。您可以看看这两个链接,了解如何使用它们:

  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/environment.html
  3. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html
  4. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

Here you have a small example:

这里有一个小例子:

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

#2


105  

<- does assignment in the current environment.

<-在当前环境中执行赋值。

When you're inside a function R creates a new environment for you. By default it includes everything from the environment in which it was created so you can use those variables as well but anything new you create will not get written to the global environment.

当你在一个函数R中,R为你创造了一个新的环境。默认情况下,它包含了创建环境中的所有内容,因此您也可以使用这些变量,但是您创建的任何新内容都不会写入全局环境。

In most cases <<- will assign to variables already in the global environment or create a variable in the global environment even if you're inside a function. However, it isn't quite as straightforward as that. What it does is checks the parent environment for a variable with the name of interest. If it doesn't find it in your parent environment it goes to the parent of the parent environment (at the time the function was created) and looks there. It continues upward to the global environment and if it isn't found in the global environment it will assign the variable in the global environment.

在大多数情况下,<< <-将分配给全局环境中已经存在的变量,或者在全局环境中创建一个变量,即使您在函数中。然而,事情并没有那么简单。它所做的是检查父环境中是否有一个名为interest的变量。如果在父环境中找不到它,它将转到父环境的父环境(在创建函数时)并在那里查找。它继续上升到全球环境,如果在全球环境中没有发现,它将在全球环境中分配变量。

This might illustrate what is going on.

这可能说明了正在发生的事情。

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"

The first time we print bar we haven't called foo yet so it should still be global - this makes sense. The second time we print it's inside of foo before calling baz so the value "in foo" makes sense. The following is where we see what <<- is actually doing. The next value printed is "in baz - before <<-" even though the print statement comes after the <<-. This is because <<- doesn't look in the current environment (unless you're in the global environment in which case <<- acts like <-). So inside of baz the value of bar stays as "in baz - before <<-". Once we call baz the copy of bar inside of foo gets changed to "in baz" but as we can see the global bar is unchanged. This is because the copy of bar that is defined inside of foo is in the parent environment when we created baz so this is the first copy of bar that <<- sees and thus the copy it assigns to. So <<- isn't just directly assigning to the global environment.

我们第一次打印bar,我们还没有调用foo,所以它仍然是全局的,这是有意义的。在调用baz之前,我们第二次打印它的内部,所以“foo”的值是有意义的。下面是我们看到<<-实际上在做什么。下一个被打印的值是“在baz -之前<-”,即使打印语句在<< <-之后。这是因为<< <-不查看当前环境(除非您在全局环境中,在这种情况下<<-的行为类似<-)。因此,在baz内bar的值保持为“在baz -之前<-”。一旦我们调用baz foo里面的bar的拷贝就会变成"in baz"但是我们可以看到全局bar是不变的。这是因为在foo中定义的bar的拷贝在我们创建baz时位于父环境中,所以这是<< <-看到的bar的第一个拷贝,因此是它分配给的拷贝。所以<<-不是直接赋值给全局环境。

<<- is tricky and I wouldn't recommend using it if you can avoid it. If you really want to assign to the global environment you can use the assign function and tell it explicitly that you want to assign globally.

<<-很棘手,如果你能避免使用它,我不推荐使用它。如果您真的想要赋值给全局环境,您可以使用assign函数并明确告诉它您想要赋值全局。

Now I change the <<- to an assign statement and we can see what effect that has:

现在我将<< <-转换为一个赋值语句,我们可以看到它有什么影响:

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"

So both times we print bar inside of foo the value is "in foo" even after calling baz. This is because assign never even considered the copy of bar inside of foo because we told it exactly where to look. However, this time the value of bar in the global environment was changed because we explicitly assigned there.

因此,我们在foo中打印bar的值,在调用baz之后,它的值是“foo”。这是因为赋值从来没有考虑过foo内部的bar的副本,因为我们告诉它确切的位置。但是,这一次全局环境中的bar的值发生了更改,因为我们在那里显式地分配了bar。

Now you also asked about creating local variables and you can do that fairly easily as well without creating a function... We just need to use the local function.

现在,您还需要创建局部变量,并且您可以很容易地做到这一点,而无需创建一个函数……我们只需要使用局部函数。

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

#3


0  

A bit more along the same lines

沿着同样的路线多一点

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

will print "1"

将打印“1”

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

Will print "20"

将打印“20”

#1


113  

Variables declared inside a function are local to that function. For instance:

函数中声明的变量是该函数的局部变量。例如:

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

gives the following error: Error: object 'bar' not found.

给出以下错误:错误:未找到对象'bar'。

If you want to make bar a global variable, you should do:

如果你想让bar成为一个全局变量,你应该这样做:

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

In this case bar is accessible from outside the function.

在这种情况下,bar可以从函数外部访问。

However, unlike C, C++ or many other languages, brackets do not determine the scope of variables. For instance, in the following code snippet:

但是,与C、c++或其他许多语言不同,括号不能确定变量的范围。例如,在下面的代码片段中:

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

y remains accessible after the if-else statement.

在if-else语句之后,y仍然是可访问的。

As you well say, you can also create nested environments. You can have a look at these two links for understanding how to use them:

正如您所说,您还可以创建嵌套环境。您可以看看这两个链接,了解如何使用它们:

  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/environment.html
  3. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html
  4. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

Here you have a small example:

这里有一个小例子:

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

#2


105  

<- does assignment in the current environment.

<-在当前环境中执行赋值。

When you're inside a function R creates a new environment for you. By default it includes everything from the environment in which it was created so you can use those variables as well but anything new you create will not get written to the global environment.

当你在一个函数R中,R为你创造了一个新的环境。默认情况下,它包含了创建环境中的所有内容,因此您也可以使用这些变量,但是您创建的任何新内容都不会写入全局环境。

In most cases <<- will assign to variables already in the global environment or create a variable in the global environment even if you're inside a function. However, it isn't quite as straightforward as that. What it does is checks the parent environment for a variable with the name of interest. If it doesn't find it in your parent environment it goes to the parent of the parent environment (at the time the function was created) and looks there. It continues upward to the global environment and if it isn't found in the global environment it will assign the variable in the global environment.

在大多数情况下,<< <-将分配给全局环境中已经存在的变量,或者在全局环境中创建一个变量,即使您在函数中。然而,事情并没有那么简单。它所做的是检查父环境中是否有一个名为interest的变量。如果在父环境中找不到它,它将转到父环境的父环境(在创建函数时)并在那里查找。它继续上升到全球环境,如果在全球环境中没有发现,它将在全球环境中分配变量。

This might illustrate what is going on.

这可能说明了正在发生的事情。

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"

The first time we print bar we haven't called foo yet so it should still be global - this makes sense. The second time we print it's inside of foo before calling baz so the value "in foo" makes sense. The following is where we see what <<- is actually doing. The next value printed is "in baz - before <<-" even though the print statement comes after the <<-. This is because <<- doesn't look in the current environment (unless you're in the global environment in which case <<- acts like <-). So inside of baz the value of bar stays as "in baz - before <<-". Once we call baz the copy of bar inside of foo gets changed to "in baz" but as we can see the global bar is unchanged. This is because the copy of bar that is defined inside of foo is in the parent environment when we created baz so this is the first copy of bar that <<- sees and thus the copy it assigns to. So <<- isn't just directly assigning to the global environment.

我们第一次打印bar,我们还没有调用foo,所以它仍然是全局的,这是有意义的。在调用baz之前,我们第二次打印它的内部,所以“foo”的值是有意义的。下面是我们看到<<-实际上在做什么。下一个被打印的值是“在baz -之前<-”,即使打印语句在<< <-之后。这是因为<< <-不查看当前环境(除非您在全局环境中,在这种情况下<<-的行为类似<-)。因此,在baz内bar的值保持为“在baz -之前<-”。一旦我们调用baz foo里面的bar的拷贝就会变成"in baz"但是我们可以看到全局bar是不变的。这是因为在foo中定义的bar的拷贝在我们创建baz时位于父环境中,所以这是<< <-看到的bar的第一个拷贝,因此是它分配给的拷贝。所以<<-不是直接赋值给全局环境。

<<- is tricky and I wouldn't recommend using it if you can avoid it. If you really want to assign to the global environment you can use the assign function and tell it explicitly that you want to assign globally.

<<-很棘手,如果你能避免使用它,我不推荐使用它。如果您真的想要赋值给全局环境,您可以使用assign函数并明确告诉它您想要赋值全局。

Now I change the <<- to an assign statement and we can see what effect that has:

现在我将<< <-转换为一个赋值语句,我们可以看到它有什么影响:

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"

So both times we print bar inside of foo the value is "in foo" even after calling baz. This is because assign never even considered the copy of bar inside of foo because we told it exactly where to look. However, this time the value of bar in the global environment was changed because we explicitly assigned there.

因此,我们在foo中打印bar的值,在调用baz之后,它的值是“foo”。这是因为赋值从来没有考虑过foo内部的bar的副本,因为我们告诉它确切的位置。但是,这一次全局环境中的bar的值发生了更改,因为我们在那里显式地分配了bar。

Now you also asked about creating local variables and you can do that fairly easily as well without creating a function... We just need to use the local function.

现在,您还需要创建局部变量,并且您可以很容易地做到这一点,而无需创建一个函数……我们只需要使用局部函数。

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

#3


0  

A bit more along the same lines

沿着同样的路线多一点

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

will print "1"

将打印“1”

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

Will print "20"

将打印“20”