R中的全局和局部variables
我是R的新手,我对R中局部和全局variables的使用感到困惑。
我在互联网上看到一些post说如果我使用=
或<-
我将分配在当前环境中的variables,并与<<-
我可以访问一个函数内的全局variables。
然而,正如我记得在C ++局部variables出现,每当你在括号{}
内声明一个variables,所以我想知道这是否相同的R? 还是只是在R中的函数 ,我们有局部variables的概念。
我做了一个小实验,这似乎表明,只有括号是不够的,我有什么问题吗?
{ x=matrix(1:10,2,5) } print(x[2,2]) [1] 4
在函数中声明的variables是该函数的局部variables。 例如:
foo <- function() { bar <- 1 } foo() bar
给出以下错误: Error: object 'bar' not found
。
如果你想使bar
变成全局variables,你应该这样做:
foo <- function() { bar <<- 1 } foo() bar
在这种情况下, bar
可以从函数外部访问。
但是,与C,C ++或许多其他语言不同,括号不能确定variables的范围。 例如,在以下代码片段中:
if (x > 10) { y <- 0 } else { y <- 1 }
y
在if-else
语句之后仍然可以访问。
正如你所说,你也可以创build嵌套的环境。 你可以看看这两个链接,了解如何使用它们:
- http://stat.ethz.ch/R-manual/R-devel/library/base/html/environment.html
- 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
<-
在当前环境中进行分配。
当你在一个函数里时,R为你创build一个新的环境。 默认情况下,它包含创build它的环境中的所有内容,以便您可以使用这些variables,但是创build的任何新内容都不会写入全局环境。
在大多数情况下, <<-
将分配给已经在全局环境中的variables,或者在全局环境中创build一个variables,即使你在一个函数内。 但是,这不是那么简单。 它所做的是检查具有感兴趣的名称的variables的父级环境。 如果它没有在你的父环境中find它,它会转到父环境的父(在创build函数的时候)并且看起来在那里。 它继续向上的全球环境,如果没有在全球环境中find它将分配variables在全球环境。
这可能说明发生了什么事情。
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"
我们第一次打印吧,我们还没有叫foo
,所以它应该仍然是全球性的 – 这是有道理的。 第二次,我们打电话给baz
之前打印它在foo
里面,所以“in foo”的值是有道理的。 以下是我们看到什么<<-
实际上在做什么。 打印的下一个值是“in baz – before << – ”,即使打印语句在<<-
。 这是因为<<-
不看当前的环境(除非你在全球环境中,在这种情况下<<-
就像<-
)。 所以baz
的价值在巴兹 – “之前”保持不变。 一旦我们打电话给baz
里面的酒吧的副本改为“巴斯”,但我们可以看到,全球bar
是不变的。 这是因为当我们创buildbaz
时,在foo
定义的bar
的副本在父环境中,所以这是<<-
看到的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
里面打印条,即使在调用baz
之后,它的值也是“in foo”。 这是因为assign
从来没有考虑过foo里的bar
的副本,因为我们已经知道在哪里看。 然而,这一次在全球环境中bar的价值已经被改变了,因为我们明确地在那里分配了。
现在你也问了关于创build局部variables的问题,你也可以很容易地做到这一点,而无需创build一个函数…我们只需要使用local
函数。
bar <- "global" # local will create a new environment for us to play in local({ bar <- "local" print(bar) }) #[1] "local" bar #[1] "global"