问题描述
让 x 在全局环境中:
x <-2
x
[1] 2
让 a
成为在本地定义另一个 x
并使用 get
的函数:
Let a
be a function that defines another x
locally and uses get
:
a<-function(){
x<-1
get("x")
}
该函数正确地从本地环境获取x
:
This function correctly gets x
from the local enviroment:
a()
[1] 1
现在让我们定义一个函数 b
如下,它使用 mapply
和 get
:
Now let's define a function b
as below, that uses mapply
with get
:
b<-function(){
x<-1
mapply(get,"x")
}
如果我调用b
,似乎mapply
使得get
没有先搜索函数环境.相反,它会尝试直接从全局环境中获取 x
,如果 x
未在全局环境中定义,则会给出错误消息:
If I call b
, it seems that mapply
makes get
not search the function environment first. Instead, it tries to get x
directly form the global enviroment, and if x
is not defined in the global env, it gives an error message:
b()
x
2
rm(x)
b()
Error in (function (x, pos = -1L, envir = as.environment(pos), mode = "any", :
object 'x' not found
对此的解决方案是明确定义envir=environment()
.
The solution to this is to explicitly define envir=environment()
.
c<-function(){
x<-1
mapply(get,"x", MoreArgs = list(envir=environment()))
}
c()
x
1
但我想知道这里到底发生了什么.mapply
在做什么?(为什么?这是预期的行为吗?)这种陷阱"在其他 R 函数中是否常见?
But I would like to know what exactly is going on here. What is mapply
doing? (And why? is this the expected behavior?) Is this "pitfall" common in other R functions?
推荐答案
问题在于 get
会查看它调用的环境,但我们在这里传递了 get
到 mapply
,然后从 mapply
中的本地环境调用 get
.如果 x
在 mapply
本地环境中没有找到,那么它会查看它的父环境,即进入 environment(mapply)
(其中是定义 mapply 的词法环境,其中是基本命名空间环境);如果它也不存在,它会查看它的父级,即全局环境,即您的 R 工作区.
The problem is that get
looks into the envivornment that its called from but here we are passing get
to mapply
and then calling get
from the local environment within mapply
. If x
is not found within the mapply
local environment then it looks the into the parent environment of that, i.e. into environment(mapply)
(which is the lexical environment that mapply was defined in which is the base namespace environment); if it is not there either, it looks into the parent of that, which is the global environment, i.e. your R workspace.
这是因为 R 使用了词法范围,相对于动态范围.
This is because R uses lexical scoping, as opposed to dynamic scoping.
我们可以通过获取存在于 mapply
中的变量来显示这一点.
We can show this by getting a variable that exists within mapply
.
x <- 2
b2<-function(){
x<-1
mapply(get, "USE.NAMES")
}
b2() # it finds USE.NAMES in mapply
## USE.NAMES
## TRUE
除了问题中显示的涉及 MoreArgs
的解决方法之外,这也有效,因为它会导致搜索在找不到 b
后查看本地环境 .(这只是为了说明正在发生的事情,在实际实践中,我们更喜欢问题中显示的解决方法.)
In addition to the workaround involving MoreArgs
shown in the question this also works since it causes the search to look into the local environment within b
after failing to find it mapply
. (This is just for illustrating what is going on and in actual practice we would prefer the workaround shown in the question.)
x <- 2
b3 <-function(){
x<-1
environment(mapply) <- environment()
mapply(get, "x")
}
b3()
## 1
添加 扩展说明.另请注意,我们可以像这样查看环境链:
ADDED Expanded explanation. Also note that we can view the chain of environments like this:
> debug(get)
> b()
debugging in: (function (x, pos = -1L, envir = as.environment(pos), mode = "any",
inherits = TRUE)
.Internal(get(x, envir, mode, inherits)))(dots[[1L]][[1L]])
debug: .Internal(get(x, envir, mode, inherits))
Browse[2]> envir
<environment: 0x0000000021ada818>
Browse[2]> ls(envir) ### this shows that envir is the local env in mapply
[1] "dots" "FUN" "MoreArgs" "SIMPLIFY" "USE.NAMES"
Browse[2]> parent.env(envir) ### the parent of envir is the base namespace env
<environment: namespace:base>
Browse[2]> parent.env(parent.env(envir)) ### and grandparent of envir is the global env
<environment: R_GlobalEnv>
因此,可能遵循的环境祖先是这样的(箭头指向父环境):
Thus, the ancestory of environments potentially followed is this (where arrow points to parent):
local environment within mapply --> environment(mapply) --> .GlobalEnv
其中 environment(mapply)
等于 asNamespace("base")
,基本命名空间环境.
where environment(mapply)
equals asNamespace("base")
, the base namespace environment.
这篇关于R 中的环境,映射和获取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!