与函数相关的环境

不仅是全局环境,函数环境也会控制符号的查找。有 3 个与函数及其运行过程相关的
重要环境:执行环境(executing environment)、封闭环境(enclosing environment)和调用
环境(calling environment)。
每次调用函数时,R 都会创建一个新的环境来主管函数的执行过程,这就是函数调用
的执行环境。函数的参数和在函数中创建的变量实际上是执行环境中的变量。
与其他环境一样,函数的执行环境也有父环境。该父环境也称为函数的封闭环境,即
定义函数的环境。这意味着在函数执行期间,任何未在执行环境中定义的变量都会到封闭
环境中查找,这正是词法作用域的机理。
有时,了解调用环境(即调用函数的环境)是很有用的,可以使用 parent.frame( )
来获取当前执行函数的调用环境。
为了说明这些概念,我们定义如下函数:
simple_fun <- function() {
cat("Executing environment: ")
print(environment())
cat("Enclosing environment: ")
print(parent.env(environment()))
}
该函数仅用来输出当它被调用时的执行环境和封闭环境:
simple_ _fun()
## Executing environment: <environment: 0x0000000014955db0>
## Enclosing environment: <environment: R_GlobalEnv>
simple_ _fun()
## Executing environment: <environment: 0x000000001488f430>
## Enclosing environment: <environment: R_GlobalEnv>
simple_ _fun()
## Executing environment: <environment: 0x00000000146a23c8>
## Enclosing environment: <environment: R_GlobalEnv>
可以看到每次调用函数时,其执行环境都在变化,但封闭环境是相同的。事实上,在
定义函数时,其封闭环境也同时被确定。我们可以调用 environment( ) 函数来获取一
个函数的封闭环境:
environment(simple_fun)
## <environment: R_GlobalEnv>
以下示例涉及 3 个嵌套函数的 3 个环境。每个函数的执行环境,封闭环境和调用环境都
会被输出。如果很扎实地理解了这些概念,可以试着猜猜看哪些是相同的,哪些是不同的:
f1 <- function() {
cat("[f1] Executing in ")
print(environment())
cat("[f1] Enclosed by ")
print(parent.env(environment()))
cat("[f1] Calling from ")
print(parent.frame())
f2 <- function() {
cat("[f2] Executing in ")
print(environment())
cat("[f2] Enclosed by ")
print(parent.env(environment()))
cat("[f2] Calling from ")
print(parent.frame())
}
f3 <- function() {
cat("[f3] Executing in ")
print(environment())
cat("[f3] Enclosed by ")
print(parent.env(environment()))
cat("[f3] Calling from ")
print(parent.frame())
f2()
}
f3()
}
我们调用 f1( )看一下输出结果,需要花点功夫从最初的输出结果中提取信息。为了
方便阅读,我们将输出结果分成几块,但是不改变输出顺序。
注意,临时创建的环境只有内存地址(例如,0x0000000016a39fe8),没有像全局环境
(R_GlobalEnv)这样的通用名称。为了更容易识别相同的环境,我们在环境输出文本的
末尾添加标记以示区别,例如相同的内存地址添加相同的标签(例如*A):
f1()
## [f1] Executing in <environment: 0x0000000016a39fe8> *A
## [f1] Enclosed by <environment: R_GlobalEnv>
## [f1] Calling from <environment: R_GlobalEnv>
当我们调用 f1( ) 时,函数会输出与 f1( ) 相关的环境,然后定义函数 f2( )和
f3( ),最后调用 f3( ) 时,继续输出如下结果:
## [f3] Executing in <environment: 0x0000000016a3def8> *B
## [f3] Enclosed by <environment: 0x0000000016a39fe8> *A
## [f3] Calling from <environment: 0x0000000016a39fe8> *A
函数 f2( )在 f3( )中被调用,接着输出如下结果:
## [f2] Executing in <environment: 0x0000000016a41f90> *C
## [f2] Enclosed by <environment: 0x0000000016a39fe8> *A
## [f2] Calling from <environment: 0x0000000016a3def8> *B
输出结果说明了如下事实:
• f1( )的封闭环境和调用环境都是全局环境;
• f3( )的封闭环境和调用环境与 f2( )的封闭环境和 f1( )的执行环境相同;
• f2( )的调用环境和 f3( )的执行环境相同。
这些又等同于如下事实:
• f1( )在全局环境被定义和调用;
• f3( )在 f1( )中被定义并调用;
• f2( )在 f1( )中被定义,但在 f3( )中被调用。

posted @ 2019-02-11 10:18  NAVYSUMMER  阅读(148)  评论(0)    收藏  举报
交流群 编程书籍