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

Global and local variables in R

提问人:Vokram 提问时间:6/6/2012 更新时间:3/15/2018 访问量:188830

问:

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

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

但是,正如我记得在 C++ 中,每当您在括号内声明变量时,都会出现局部变量,所以我想知道 R 是否也是如此?或者只是对于 R 中的函数,我们有局部变量的概念。{}

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

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

评论

0赞 isomorphismes 3/19/2015
除了这些答案之外,还要运行一些代码:,...globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env
0赞 Aaron McDaid 7/21/2016
@isomorphismes, .这是另一种形式的分配吗?Error: could not find function "%>%"
1赞 Henrik 1/6/2017
R-help上的相关主题:“<<-”运算符是什么意思?
2赞 isomorphismes 3/4/2017
@AaronMcDaid 您好,很抱歉没有早点回复!那是从.这是一种在右侧 () 而不是左侧 () 应用函数的方法。require(magrittr)x | f1 | f2 | f3f3( f2( f1( x ) ) )

答:

180赞 betabandido 6/6/2012 #1

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

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
}

y在声明之后仍然可访问。if-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
156赞 Dason 6/6/2012 #2

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

当你在函数中时,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"

我们第一次打印酒吧时,我们还没有调用,所以它应该仍然是全局的 - 这是有道理的。我们第二次打印它是在调用之前的内部,所以值“in foo”是有意义的。以下是我们看到实际在做什么的地方。打印的下一个值是“in baz - before <<-”,即使 print 语句位于 .这是因为在当前环境中不看(除非您在全局环境中,在这种情况下,就像 )。因此,在酒吧的值内保持为“在 baz - << 之前”。一旦我们调用 bar 的副本,里面的 bar 就会更改为“in baz”,但正如我们所看到的,全局是不变的。这是因为当我们创建时,在 中定义的副本位于父环境中,因此这是它看到的第一个副本,因此它分配给的副本。所以不仅仅是直接分配给全球环境。foofoobaz<<-<<-<<-<<-<-bazbazfoobarbarfoobazbar<<-<<-

<<-很棘手,如果可以避免,我不建议使用它。如果确实要分配给全局环境,可以使用 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"

因此,即使在调用 之后,我们两次打印值内部的条形图都是“in foo”。这是因为从来没有考虑过 foo 内部的副本,因为我们告诉它确切地在哪里看。但是,这一次全局环境中的 bar 值发生了变化,因为我们在那里显式分配了 bar。foobazassignbar

现在您还询问了创建局部变量的问题,您也可以在不创建函数的情况下轻松完成此操作......我们只需要使用这个函数。local

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

评论

0赞 Mojimi 11/23/2021
我是否可以以内部环境与外部环境相同的方式配置函数?这意味着使用 <- 创建的任何变量都可以在它之外使用
0赞 Dason 11/23/2021
有点是的,但这是一个糟糕的主意。我不会帮你,因为它太糟糕了。最好返回结果并让用户决定如何使用它们。
5赞 SemanticBeeng 3/15/2018 #3

沿着同样的思路再多一点

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”