R中环境的图片表示?
Picture representation of environments in R?
拜托,你能帮我理解书面的形象(环境是如何工作的)吗?:
enclosing <- function() {
z <- 2
function(x, y = x) {
x + y + z
}
}
f <- enclosing()
calling <- function() {
w <- 5
f(x = 2 * w)
}
calling()
## [1] 22
The explanation in the book is the following:
You start out in the global environment where you define enclosing to be
a function. When you call enclosing, you create an evaluation environment
in which you store the variable z and then return a function that you store in
the global environment as f. Since this function was defined in the evaluation
environment of enclosing, this environment is the environment of f.
Then you create calling, store that in the global environment, and call
it. This creates, once again, an evaluation environment. In this, you store the
variable w and then call f. You don’t have f in the evaluation environment, but
because the parent of the evaluation environment is the global environment, you
can find it. When you call f, you give it the expression 2 * w as parameter x.
Inside the call to f, you have another evaluation environment. Its parent is
the closure you got from enclosing. Here you need to evaluate f’s body: x + y + z.
However, before that, the evaluation environment needs to be set up. Since x
and y are formal parameters, they will be stored in the evaluation environment
as promises. You provided x as a parameter when you called f, so this promise
must be evaluated in the calling environment (the environment inside
calling), while y has the default value, so it must be evaluated in the evaluation
environment. In this environment, it can see x and y and through the parent
environment z. You evaluate x, which is the expression 2 * w in the calling
environment, where w is known, and you evaluate y in the local environment,
where x is known. So, you can get the value of those two variables and then get z
from the enclosing environment.
我的尝试是这样的:
Environment representation
环境树
环境的层次结构如下图所示。也就是说,enclosing 和 calling 是全局环境的子项,anonymous(等于 f)是 enclosing 的子项。
Environment hierarchy
.GlobalEnv
enclosing
anonymous == f
calling
我们可以通过检测函数来验证这些关系:
library(pryr)
enclosing <- function() {
e <- environment(); attr(e, "name") <- "enclosing"
cat("envir:", environmentName(e),
"address:", address(e),
"parent:", environmentName(parent.env(e)),
"parent frame:", environmentName(parent.frame())), "\n")
z <- 2
function(x, y = x) {
e <- environment(); attr(e, "name") <- "anon"
cat("envir:", environmentName(e),
"address:", address(e),
"parent:", environmentName(parent.env(e)),
"parent frame:", environmentName(parent.frame()), "\n")
x + y + z
}
}
f <- enclosing()
calling <- function() {
e <- environment(); attr(e, "name") <- "calling"
cat("envir:", environmentName(e),
"address:", address(e),
"parent:", environmentName(parent.env(e)),
"parent frame:", environmentName(parent.frame()), "\n")
w <- 5
f(x = 2 * w)
}
calling()
上面运行的输出是:
envir: enclosing address: 0x11ee1fd8 parent: R_GlobalEnv parent frame: R_GlobalEnv
envir: calling address: 0x8da2ee0 parent: R_GlobalEnv parent frame: R_GlobalEnv
envir: anon address: 0x8da0ae8 parent: enclosing parent frame: calling
[1] 22
以上输出显示
- 调用函数时创建的运行时间环境(或求值环境)
- 它在内存中的地址——如果你运行这个你的地址会不同
- 运行 时间环境的父级(或封闭环境)
- 调用方的环境或父框架
每个环境都有一个parent,输出显示封装和调用的父是全局环境,anon的父是封装。
上面每个函数被调用一次;但是,如果一个函数被调用两次,那么每次 运行 时间环境都会不同。我们能够分辨出这一点,因为即使我们用相同的名称命名了两个实例,检测输出的地址也会不同。
例如,每次调用 calling
时,都会为该执行实例创建一个新的 运行 时间环境,上面的代码会将 运行 时间环境命名为 calling
但我们可以通过不同的地址来区分这两个实例。
另一方面,运行 时间环境的父级是定义函数的环境,因此它不会从一次调用更改为下一次调用。因此,如果我们要调用 calling
两次,则会创建两个不同的 运行 时间环境——检测代码的输出会将它们命名为 calling
但我们可以区分它们,因为它们会在输出中有不同的地址。这两个调用都将全局环境作为它们的父级,因为 calling
是在全局环境中定义的。
请注意,f
被分配了在 enclosing
中定义的匿名函数,因此即使对名称 f
的分配发生在全局环境中,它的定义(参数,正文等)发生在 enclosing
.
请注意,函数的 运行 时间环境有时称为 evaluation environment and the parent environment is sometimes called the enclosing environment。
您可能想要查看的有用博客 post 是 http://blog.obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/
函数调用
父框架是调用者的环境,即调用当前函数的函数执行实例中的运行时间环境。父框架不一定与父框架相同。当 R 搜索对象时,它会在当前环境中搜索,如果找不到,那么它会在父环境中查找,如果仍未找到,则在祖先树的更上方查找。 R 不在父框架中搜索,因此父框架及其调用树与环境的层次结构无关。
Call tree
.GlobalEnv
enclosing
calling
anonymous == f
我想我们可以通过一个例子更好地理解全局、封闭和评估环境之间的关系。我稍微修改了 OP 中的示例。
z
的值未存储在全局环境中,但它在调用之间仍然存在。 z
的值存储在封闭环境中。
enclosing <- function(a) {
z <- a
function(x, y = x) {
z <- x + y + z #This value z will not persist between calls of f.
}
}
f <- enclosing(2)
calling <- function() {
w <- 5
f(x = 2 * w)
}
n <- calling() #no change in value of z
## [1] 22
n <- calling()
## [1] 22 value of z persisted in enclosing environment between call.
f <- enclosing(4) #value of z is changed to 4 now
n <- calling()
## [1] 24
n <- calling()
## [1] 24 value of z persisted in enclosing environment between call.
拜托,你能帮我理解书面的形象(环境是如何工作的)吗?:
enclosing <- function() {
z <- 2
function(x, y = x) {
x + y + z
}
}
f <- enclosing()
calling <- function() {
w <- 5
f(x = 2 * w)
}
calling()
## [1] 22
The explanation in the book is the following: You start out in the global environment where you define enclosing to be a function. When you call enclosing, you create an evaluation environment in which you store the variable z and then return a function that you store in the global environment as f. Since this function was defined in the evaluation environment of enclosing, this environment is the environment of f. Then you create calling, store that in the global environment, and call it. This creates, once again, an evaluation environment. In this, you store the variable w and then call f. You don’t have f in the evaluation environment, but because the parent of the evaluation environment is the global environment, you can find it. When you call f, you give it the expression 2 * w as parameter x. Inside the call to f, you have another evaluation environment. Its parent is the closure you got from enclosing. Here you need to evaluate f’s body: x + y + z. However, before that, the evaluation environment needs to be set up. Since x and y are formal parameters, they will be stored in the evaluation environment as promises. You provided x as a parameter when you called f, so this promise must be evaluated in the calling environment (the environment inside calling), while y has the default value, so it must be evaluated in the evaluation environment. In this environment, it can see x and y and through the parent environment z. You evaluate x, which is the expression 2 * w in the calling environment, where w is known, and you evaluate y in the local environment, where x is known. So, you can get the value of those two variables and then get z from the enclosing environment.
我的尝试是这样的:
Environment representation
环境树
环境的层次结构如下图所示。也就是说,enclosing 和 calling 是全局环境的子项,anonymous(等于 f)是 enclosing 的子项。
Environment hierarchy
.GlobalEnv
enclosing
anonymous == f
calling
我们可以通过检测函数来验证这些关系:
library(pryr)
enclosing <- function() {
e <- environment(); attr(e, "name") <- "enclosing"
cat("envir:", environmentName(e),
"address:", address(e),
"parent:", environmentName(parent.env(e)),
"parent frame:", environmentName(parent.frame())), "\n")
z <- 2
function(x, y = x) {
e <- environment(); attr(e, "name") <- "anon"
cat("envir:", environmentName(e),
"address:", address(e),
"parent:", environmentName(parent.env(e)),
"parent frame:", environmentName(parent.frame()), "\n")
x + y + z
}
}
f <- enclosing()
calling <- function() {
e <- environment(); attr(e, "name") <- "calling"
cat("envir:", environmentName(e),
"address:", address(e),
"parent:", environmentName(parent.env(e)),
"parent frame:", environmentName(parent.frame()), "\n")
w <- 5
f(x = 2 * w)
}
calling()
上面运行的输出是:
envir: enclosing address: 0x11ee1fd8 parent: R_GlobalEnv parent frame: R_GlobalEnv
envir: calling address: 0x8da2ee0 parent: R_GlobalEnv parent frame: R_GlobalEnv
envir: anon address: 0x8da0ae8 parent: enclosing parent frame: calling
[1] 22
以上输出显示
- 调用函数时创建的运行时间环境(或求值环境)
- 它在内存中的地址——如果你运行这个你的地址会不同
- 运行 时间环境的父级(或封闭环境)
- 调用方的环境或父框架
每个环境都有一个parent,输出显示封装和调用的父是全局环境,anon的父是封装。
上面每个函数被调用一次;但是,如果一个函数被调用两次,那么每次 运行 时间环境都会不同。我们能够分辨出这一点,因为即使我们用相同的名称命名了两个实例,检测输出的地址也会不同。
例如,每次调用 calling
时,都会为该执行实例创建一个新的 运行 时间环境,上面的代码会将 运行 时间环境命名为 calling
但我们可以通过不同的地址来区分这两个实例。
另一方面,运行 时间环境的父级是定义函数的环境,因此它不会从一次调用更改为下一次调用。因此,如果我们要调用 calling
两次,则会创建两个不同的 运行 时间环境——检测代码的输出会将它们命名为 calling
但我们可以区分它们,因为它们会在输出中有不同的地址。这两个调用都将全局环境作为它们的父级,因为 calling
是在全局环境中定义的。
请注意,f
被分配了在 enclosing
中定义的匿名函数,因此即使对名称 f
的分配发生在全局环境中,它的定义(参数,正文等)发生在 enclosing
.
请注意,函数的 运行 时间环境有时称为 evaluation environment and the parent environment is sometimes called the enclosing environment。
您可能想要查看的有用博客 post 是 http://blog.obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/
函数调用
父框架是调用者的环境,即调用当前函数的函数执行实例中的运行时间环境。父框架不一定与父框架相同。当 R 搜索对象时,它会在当前环境中搜索,如果找不到,那么它会在父环境中查找,如果仍未找到,则在祖先树的更上方查找。 R 不在父框架中搜索,因此父框架及其调用树与环境的层次结构无关。
Call tree
.GlobalEnv
enclosing
calling
anonymous == f
我想我们可以通过一个例子更好地理解全局、封闭和评估环境之间的关系。我稍微修改了 OP 中的示例。
z
的值未存储在全局环境中,但它在调用之间仍然存在。 z
的值存储在封闭环境中。
enclosing <- function(a) {
z <- a
function(x, y = x) {
z <- x + y + z #This value z will not persist between calls of f.
}
}
f <- enclosing(2)
calling <- function() {
w <- 5
f(x = 2 * w)
}
n <- calling() #no change in value of z
## [1] 22
n <- calling()
## [1] 22 value of z persisted in enclosing environment between call.
f <- enclosing(4) #value of z is changed to 4 now
n <- calling()
## [1] 24
n <- calling()
## [1] 24 value of z persisted in enclosing environment between call.