实际上,这与@Backlin 显示的相反:父环境是包含其他环境的环境。因此,在您定义的情况下, 的封闭环境test
是 的本地环境fn
, 的封闭环境test1
是全局环境,如下所示:
环境的行为与 R 中的其他对象不同,因为它们在传递给函数或在赋值中使用时不会被复制。环境对象本身内部由指向的指针组成:
- 一个框架(这是一个包含值的对列表)
- 封闭环境(如上所述)
- 哈希表(如果环境未哈希,则为列表或 NULL)
环境包含指针这一事实使一切变得不同。环境并不是那么容易处理,它们实际上非常棘手。看看下面的代码:
> test <- new.env()
> test$a <- 1
> test2 <- test
> test2$a <- 2
> test$a
[1] 2
test
因此,您从in复制的唯一内容test2
是指针。如果您更改 中的值test2
,您test
也会更改其中的值。(实际上,您只更改该值一次,但test
都test2
指向同一帧)。
当你试图保存一个环境时,R别无选择,只能获取框架、哈希表和封闭环境的值并保存它们。由于封闭环境本身就是一个环境,R 还将保存所有封闭环境,直到它到达全局环境。由于全局环境在内部代码中以特殊方式处理,因此(幸运的是)没有保存在文件中。
注意封闭环境和父框架之间的区别:假设我们定义我们的函数有点不同:
a <- matrix(runif(1000000, 0, 1), ncol=1000)
save(a, file="bigfile.RData")
fn <- function() {
load("bigfile.RData")
test <- new.env()
save(test, file="far-too-big.RData")
test1 <- new.env(parent=globalenv())
save(test1, file="right-size.RData")
}
fn2 <- function(){
z <- matrix(runif(1000000,0,1),ncol=1000)
fn()
}
fn2()
现在我们有以下情况:
有人会认为文件“far-too-big.RData”同时包含矩阵 a 和矩阵 z,但事实并非如此。它只包含矩阵a。这是因为封闭环境是fn
全局环境。的父框架是fn
的环境fn2
,但创建的环境对象fn
包含一个指向全局环境的指针。
另一方面,如果我们执行以下操作:
fn <- function() {
load("bigfile.RData")
test <- new.env()
test$b <- a
test2 <- new.env(parent=test)
save(test2, file="far-too-big.RData")
}
test2
现在包含在两个环境中(beingtest
和 的环境fun
),并且这两个环境也都保存在文件中。所以你得到这种情况:
不管怎样,我个人避免将环境保存为环境,因为可能出错的地方更多。在我看来,将环境保存为列表在 99.9% 的情况下是更好的选择:
fn2 <- function(){
load("bigfile.RData")
test <- new.env()
test$x <- "something"
test$fn <- ls
testlist <- as.list(test)
save(testlist, file="right-size.RData")
}
fn2()
如果你需要它是一个环境,你可以在加载时将它转换回来。
load("right-size.RData")
test <- as.environment(testlist)