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


126

我是R的新手,我对R中使用局部变量和全局变量感到非常困惑。

我在互联网上读到一些帖子,说如果我使用=<-我将在当前环境中分配变量,并且<<-可以在函数内部访问全局变量。

但是,正如我记得在C ++中,只要在方括号内声明变量{},局部变量就会出现,因此我想知道R是否相同?还是仅对于R 函数具有局部变量的概念。

我做了一个小实验,这似乎表明仅括号是不够的,我弄错了吗?

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

除了这些答案外,还需要运行一些代码:globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env,…
同构性

@isomorphismes ,Error: could not find function "%>%"。那是另一种形式的作业吗?
亚伦·麦克戴德

1
R帮助的相关主题:“ <<-”运算符是什么意思?
亨里克

1
@AaronMcDaid嗨,很抱歉没有尽快回复!那是从require(magrittr)。这是在右侧(x | f1 | f2 | f3)而不是左侧(f3( f2( f1( x ) ) ))应用功能的一种方式。
同构性

Answers:


153

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

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

给出以下错误:Error: object 'bar' not found

如果要创建bar全局变量,则应执行以下操作:

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

在这种情况下bar,可以从功能外部进行访问。

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

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

yif-else声明后仍可访问。

就像您说的那样,您也可以创建嵌套环境。您可以查看以下两个链接以了解如何使用它们:

  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

这里有一个小例子:

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

<- 在当前环境中进行分配。

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

在大多数情况下,<<-即使您在函数内部,也将分配给全局环境中已经存在的变量或在全局环境中创建变量。但是,它并不那么简单。它所做的是在父环境中检查具有所关注名称的变量。如果在您的父级环境中找不到它,它将转到父级环境的父级(在创建函数时)并在那儿查找。它继续向上到达全局环境,如果在全局环境中找不到它,它将在全局环境中分配变量。

这可能说明发生了什么。

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"

第一次打印bar时,我们尚未调用foo它,因此它仍然应该是全局的-这很有意义。第二次打印它是foo在调用之前进行的,baz因此“ in foo”中的值有意义。以下是我们看到<<-实际在做什么的地方。即使print语句在<<-。之后,下一个打印的值仍是“在baz-<<之前” 。这是因为<<-它不在当前环境中查看(除非您处于全局环境中,在这种情况下的<<-行为类似于<-)。因此baz,bar的值内部保持为“ in baz-<<-之前”。一旦我们调用baz了内部的bar副本,其副本foo将更改为“ in baz”,但正如我们看到的那样,全局变量bar未更改。bar是的内部定义foo是在父环境时,我们创造baz所以这是第一个副本bar<<-看到并因此分配给复制。因此<<-,不仅仅是直接分配给全球环境。

<<-是棘手的,如果可以避免的话,我不建议您使用它。如果您确实要分配给全局环境,则可以使用assign函数,并明确告诉您要全局分配。

现在,将更<<-改为一个assign语句,我们可以看到产生了什么效果:

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"

因此,foo即使调用后,两次我们都在值内部打印bar 为“ in foo” baz。这是因为assign从未考虑过barfoo内部的副本,因为我们告诉了它确切的位置。但是,这次更改了全局环境中bar的值,因为我们在那里明确指定了它的值。

现在,您还询问了有关创建局部变量的信息,并且无需创建函数就可以轻松地做到这一点……我们只需要使用local函数即可。

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

2

相同的地方

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

将打印“ 1”

attrs <- {}

attrs.a <- 1

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

f(20)
print(attrs.a)

将打印“ 20”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.