2017-08-02 20:40:03
作用域: 一组程序规则,定义识别符号(identifier)和实体(entity)之间的绑定(binding,即名-实映射)。作用域决定了R如何查找一个符号的值。
名称覆盖 (name masking)
首先查找函数体内的对象是否有符合对应名称的变量,如果没有的话,就再上升一层继续查找
函数和变量 (functions v.s. variables)
如果函数和变量的名称一样的话,会根据当时的语法去判断是函数还是变量
全新起始 (a fresh start)
函数每次运行,其中的变量都是重新建立的,和上次运行没有关系
动态查找 (dynamic lookup)
R 语言中,对变量的查找是在函数运行的时候进行的,而不是在建立的时候
x <- 1 f1 <- function(){ y <- 2 f2 <- function(){ z <- 3 c(x, y, z) } f2() } f1()
## [1] 1 2 3
x <- 1; y <- 4; z <- 5 f1 <- function(){ y <- 2; z <- 6 f2 <- function(){ z <- 3 c(x, y, z) } f2() } f1()
## [1] 1 2 3
函数和变量一视同仁
f1 <- function(x) x+1 f2 <- function(){ f1 <- 10 f1(f1) } f2()
## [1] 11
c(c=c)
## $c ## function (...) .Primitive("c")
每次运行f()
,会生成一个新的环境
f <- function(){ if (exists("x")) x <- x + 1 else x <- 1 x } f()
## [1] 2
f()
## [1] 2
codetools::findGlobals()
查看非自包含函数的外部依赖f()的运算过程依赖外部对象x
f <- function() x x <- 1; f()
## [1] 1
x <- 2; f()
## [1] 2
codetools::findGlobals(f)
## [1] "x"
甚至可以覆写函数/算符
"+" <- `c` 1+1
## [1] 1 1
1:2 + c("a", "b")
## [1] "1" "2" "a" "b"
环境就是一组名-实绑定。
e <- new.env(); e
<environment: 0x0000000026a45c78>
e$a <- FALSE e$b <- 1:2 e$c <- e$b ls.str(e)
a : logi FALSE b : int [1:2] 1 2 c : int [1:2] 1 2
$
或[[
访问对象as.list
和as.environment
相互转换特殊环境
globalenv()
:baseenv()
:emptyenv()
: 空环境environment()
: 当前环境search()
searchpaths()
可查看搜索路径parent.env()
查看父环境
searchpaths()
## [1] ".GlobalEnv" "/usr/lib/R/library/stats" ## [3] "/usr/lib/R/library/graphics" "/usr/lib/R/library/grDevices" ## [5] "/usr/lib/R/library/utils" "/usr/lib/R/library/datasets" ## [7] "/usr/lib/R/library/methods" "Autoloads" ## [9] "/usr/lib/R/library/base"
创建环境e
e <- new.env()
环境内创建对象
e$a <- FALSE e[['b']] <- 1:2 assign(".c", e$b, envir=e)
查看环境(默认不显示e$.c)
ls.str(e, all.names=TRUE)
.c : int [1:2] 1 2 a : logi FALSE b : int [1:2] 1 2
判断某对象是否存在
exists(".c", envir=e)
两个环境是否相同
identical(environment(), globalenv())
找父环境
parent.env(e)
<environment: R_GlobalEnv>
删除
rm("a", envir=e)
e1 <- new.env(parent=globalenv()) e2 <- new.env(parent=e1) e3 <- new.env(parent=e2) e1$x <- 1 e2$y <- 2 e3$x <- 3 e1; e2; e3
<environment: 0x3e00da0> <environment: 0x3d9c6b8> <environment: 0x3d45810>
用一个递归算法,层层向上查找
find_up <- function(name, env){ if (exists(name, envir=env, inherits=FALSE)) env else find_up(name, parent.env(env)) }
find_up("x", e3)
## <environment: 0x3d45810>
find_up("y", e3)
## <environment: 0x3d9c6b8>
find_up("plot", e3)
## <environment: package:graphics> ## attr(,"name") ## [1] "package:graphics" ## attr(,"path") ## [1] "/usr/lib/R/library/graphics"
闭包环境(enclosing environment)
绑定环境 (binding environment)
<-
将函数定义绑定给一个名称,定义出一个绑定环境执行环境 (execution environment)
调用环境 (calling environment)
environment()
获得函数的闭包环境f <- function(x) x+y environment(f)
## <environment: R_GlobalEnv>
# f的闭包环境是globalevn()
e <- new.env(parent=globalenv()) e$f <- function() 0 # e$f的绑定环境为e,但闭包环境是globalenv()
f <- function(x){ cat("执行环境:\n") print(environment()) print(list("0> init"= ls.str(environment()))) a <- 10 print(list("1> a <- 10"= ls.str(environment()))) o <- x + a print(list("2> o <- x + a"= ls.str(environment()))) return(o) } f(5)
## 执行环境: ## <environment: 0x3e8bfa8> ## $`0> init` ## x : num 5 ## ## $`1> a <- 10` ## a : num 10 ## x : num 5 ## ## $`2> o <- x + a` ## a : num 10 ## o : num [1:2] 5 10 ## x : num 5
## [1] 5 10
a <- 1 f <- function(){ a <- 2 cat("f()\n") print(environment()) cat("执行:", get("a", environment()), "\n") print(parent.frame()) cat("调用:", get("a", parent.frame()), "\n") g <- function() { a <- 3 cat("\ng()\n") print(environment()) cat("执行:", get("a", environment()), "\n") print(parent.frame()) cat("调用:", get("a", parent.frame()), "\n") } g() }
local({cat(".GlobalEnv\n") print(environment()) cat("执行:", get("a", environment()), "\n") print(parent.frame()) cat("调用:", get("a", parent.frame()), "\n")})
## .GlobalEnv ## <environment: R_GlobalEnv> ## 执行: 1 ## <environment: R_GlobalEnv> ## 调用: 1
f()
## f() ## <environment: 0x429f3f8> ## 执行: 2 ## <environment: R_GlobalEnv> ## 调用: 1 ## ## g() ## <environment: 0x47890f8> ## 执行: 3 ## <environment: 0x429f3f8> ## 调用: 2
# 函数modify_a将一个对象的元素"a"改为2 modify_a <- function(x) invisible(x$a <- 2)
lst <- list(a=1) lst$a
## [1] 1
modify_a(lst) lst$a
## [1] 1
env <- new.env() env$a <- 1 ls.str(env)
## a : num 1
modify_a(env) ls.str(env)
## a : num 2
Thank you!