学习笔记,仅供参考,有错必纠
文章目录
- R开发
- 环境空间
- 创建一个空间
- 环境空间的层次结构
- 环境空间的特征
R开发
环境空间
环境空间是R语言中关于计算机方面的底层设计,主要用于R语言的环境加载器。通过环境空间,封装了加载器的运行过程,让使用者在不知道底层细节的情况下,可以任意加载使用到的第三方R语言程序包。
在R语言中,不管是变量、对象或者函数,都存在于R的环境空间中,R程序在运行时变量、函数都有自己的运行时空间。R语言的环境(environment)是由内核定义的一个数据结构,由一系列、有层次关系的框架(frame)组成,每个环境对应一个框架,用来区别不同的运行时空间(scope)。
环境空间有一些特征,比如每个环境空间要有唯一的名字;环境空间是引用类型,非赋值类型;环境空间都有父环境空间,空环境空间是最顶层的环境空间,没有父空间;子环境空间会继承父环境空间的变量等。
创建一个空间
通过new.env()函数可以创建一个新的环境。
语法:
new.env(hash = TRUE, parent = parent.frame(), size = 29L)
hash默认值是TRUE,使用Hash table的结构,parent指定要创建环境的父环境,size是指初始化环境空间的大小。
创建一个新环境:
R>e1 <- new.env()
R>e1
<environment: 0x00000000197c9c70>
R>class(e1)
[1] "environment"
R>otype(e1)
[1] "base"
e1环境中定义一个变量:
R>#定义变量a
R>e1$a <- 10
R>#输出变量a
R>e1$a
[1] 10
R>#列出当前环境中的变量
R>ls()
[1] "a" "b" "e1" "i" "myl" "track_a" "x" "y"
[9] "z"
R>#列出e1环境中的变量
R>ls(e1)
[1] "a"
环境空间的层次结构
R语言的环境空间是一种有层次关系的结构,每个环境都有上一层环境,直到最顶层的空环境。R语言中有5种环境的定义,即全局环境、内部环境、父环境、空环境和包环境。
-
全局环境,即用户环境,是用户程序运行的环境空间。
-
内部环境,构造出来的环境,可以是通过new.env函数显示创建的环境空间,也可以是匿名的环境空间。
-
父环境,即上一层环境,环境空间的上一层。
-
空环境,即顶层环境,没有父环境空间。
-
包环境,包封装的环境空间。
R># 当前环境
R>environment()
<environment: R_GlobalEnv>
R># 内部环境
R>e1 <- new.env()
R>e1
<environment: 0x000000001a9f6d38>
R># 父环境
R>parent.env(e1)
<environment: R_GlobalEnv>
R># 空环境
R>emptyenv()
<environment: R_EmptyEnv>
R># 包环境
R>baseenv()
<environment: base>
用search函数查看当前环境中加载的R包:
R># 查看环境空间
R>search()[1] ".GlobalEnv" "package:pryr" "tools:rstudio" "package:stats" [5] "package:graphics" "package:grDevices" "package:utils" "package:datasets" [9] "package:methods" "Autoloads" "package:base"
R>.GlobalEnv
<environment: R_GlobalEnv>
查看父环境空间:
R>#查看e1环境的父环境空间
R>parent.env(e1)
<environment: R_GlobalEnv>
R>#查看当前环境的父环境空间
R>parent.env(environment())
<environment: package:pryr>
attr(,"name")
[1] "package:pryr"
attr(,"path")
[1] "F:/software/R-3.6.2/library/pryr"
R>#查看base包环境的父环境空间
R>parent.env(baseenv())
<environment: R_EmptyEnv>
R>#查看空环境的父环境空间
R>parent.env(emptyenv())
Error in parent.env(emptyenv()) : the empty environment has no parent
R>#因没有父环境,所以出现错误
既然环境空间是有层次关系的,那么我们打印这个层次结构,从自定义的e1环境到最上层的空环境:
parent.call <- function(e) { # 递归打印父环境空间print(e)if (is.environment(e) & !identical(emptyenv(), e)){parent.call(parent.env(e))}
}parent.call(e1)#输出
<environment: 0x000000001a9f6d38>
<environment: R_GlobalEnv>
<environment: package:pryr>
attr(,"name")
[1] "package:pryr"
attr(,"path")
[1] "F:/software/R-3.6.2/library/pryr"
<environment: 0x0000000008fbca18>
attr(,"name")
[1] "tools:rstudio"
<environment: package:stats>
attr(,"name")
[1] "package:stats"
attr(,"path")
[1] "F:/software/R-3.6.2/library/stats"
<environment: package:graphics>
attr(,"name")
[1] "package:graphics"
attr(,"path")
[1] "F:/software/R-3.6.2/library/graphics"
<environment: package:grDevices>
attr(,"name")
[1] "package:grDevices"
attr(,"path")
[1] "F:/software/R-3.6.2/library/grDevices"
<environment: package:utils>
attr(,"name")
[1] "package:utils"
attr(,"path")
[1] "F:/software/R-3.6.2/library/utils"
<environment: package:datasets>
attr(,"name")
[1] "package:datasets"
attr(,"path")
[1] "F:/software/R-3.6.2/library/datasets"
<environment: package:methods>
attr(,"name")
[1] "package:methods"
attr(,"path")
[1] "F:/software/R-3.6.2/library/methods"
<environment: 0x0000000007659700>
attr(,"name")
[1] "Autoloads"
<environment: base>
<environment: R_EmptyEnv>
通过观察环境空间层次,我们还可以发现R包的加载顺序。
最先加载的是base包,然后通过base::Autoloads()函数分别加载6个基础包,上层的pryr包则是我们手动加载的,最后以R_GlobalEnv环境作为当前运行环境空间,内部环境空间是R_GlobalEnv环境的下层环境空间。
环境空间的特征
- 每个环境空间中的对象名字要唯一
在不同的环境空间中,定义变量x:
x <- 10
e1 <- new.env()
e1$x <- 20
x # 10
e1$x # 20
- 环境空间变量的赋值
把e1环境空间变量赋值给另一个变量f,再修改其环境内部变量:
#把e1赋值给f
f <- e1
#修改e1中a变量的值
e1$a <- 100
f$a #100
#比较f环境和e1环境
identical(f, e1) #TRUE
#查看e1和f的环境地址
f #<environment: 0x000000001b9253f8>
e1 #<environment: 0x000000001b9253f8>
- 定义更上层的环境空间
空环境是最顶层的环境空间,然后是base包的环境空间,我们可以尝试创建一个靠近顶层的环境空间,让父环境空间是base包的环境空间:
parent.call <- function(e) { # 递归打印父环境空间print(e)if (is.environment(e) & !identical(emptyenv(), e)){parent.call(parent.env(e))}
}
#创建e2环境,以base为父环境
e2 <- new.env(parent = baseenv())
#查看e2环境的父环境列表
parent.call(e2)
#输出
<environment: 0x0000000012018a70>
<environment: base>
<environment: R_EmptyEnv>
- 子环境空间会继承父环境空间的变量
x <- 1:5
e1 <- new.env()
e1$x <- 10
e1$fun <- function(y) {print("e1::fun")x <<- y
}
e1$fun(20) #"e1::fun"
x #20
e1$x #10
我们可以使用<<-
修改父环境空间的变量值,但是用<-
却不能进行这样的操作。