R中的环境,应用和获取 [英] Environments in R, mapply and get
问题描述
在全球环境中让 x <-2
:
x <-2
x
[1] 2
设 a
是一个在本地定义另一个 x
并使用 get
:
a <-function(){
x <-1
get(x)
$ b 这个函数正确地得到 x
来自当地的环境:
a()
[1] 1
现在让我们定义一个函数 b
,如下所示,它使用 mapply with get
:
b < - <函数(){
x <-1
mapply(get,x)
}
如果我调用 b
,看起来 mapply
会使得到
不首先搜索功能环境。相反,它试图直接从全局环境中获取 x
,并且如果未在全局环境中定义 x
(b)
b()
x
2
rm(x)
b()
错误in(function(x,pos = -1L,envir = as.environment(pos),mode =any,:
object'x'not found
解决方案是显式定义 envir = environment()$ c
$ p $ c <-function(){
x <-1
mapply(get ,x,MoreArgs = list(envir = environment()))
}
c()
x
1
但是我想知道这里究竟发生了什么。 mapply
是干什么的? (为什么?这是预期的行为?)这是其他R函数常见的陷阱吗?
问题是 get
查看其从中调用的环境,但在这里我们传递了从
。如果在中的本地环境获取
到 mapply
,然后调用获得
> mapply mapply
本地环境中未找到 x
,那么它会查找该环境的父环境,即 environment(mapply)
(这是在基本命名空间环境中定义了mapply的词法环境);如果它不在那里,它会查看它的父级,即全局环境,即你的R工作区。
这是因为R使用了词法范围界定,与动态范围界定相反。
我们可以通过获取一个存在于 mapply
中的变量来显示它。
x < - 2
b2 < - function(){
x <-1
mapply(get,USE.NAMES)
}
b2()#它在mapply中找到USE.NAMES
## USE.NAMES
## TRUE
除了涉及 MoreArgs
这个问题也适用,因为它会导致搜索在找不到 mapply
之后查看 b
中的本地环境。 (这只是为了说明发生了什么,在实际操作中我们更喜欢问题中显示的解决方法。)
x < - 2
b3< -function(){
x< -1
environment(mapply)< - environment()
mapply(get,x)
b3()
## 1
添加扩展说明。另请注意,我们可以查看如下环境链:
>调试(获取)
> b()
调试:(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))
浏览[2]> envir
< environment:0x0000000021ada818>
浏览[2]> ls(envir)###这表明envir是mapply中的本地环境
[1]dotsFUNMoreArgsSIMPLIFYUSE.NAMES
浏览[2]> ; parent.env(envir)### envir的父节点是基本命名空间env
< environment:namespace:base>
浏览[2]> parent.env(parent.env(envir))###和envir的祖父母是全局环境
< environment:R_GlobalEnv>
因此,可能遵循的环境祖先就是这样(箭头指向父项):
mapply内的本地环境 - >环境(mapply) - > .GlobalEnv
其中环境(mapply)
等于 asNamespace(base)
,即基本命名空间环境。
Let x<-2
in the global env:
x <-2
x
[1] 2
Let a
be a function that defines another x
locally and uses get
:
a<-function(){
x<-1
get("x")
}
This function correctly gets x
from the local enviroment:
a()
[1] 1
Now let's define a function b
as below, that uses mapply
with get
:
b<-function(){
x<-1
mapply(get,"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
The solution to this is to explicitly define envir=environment()
.
c<-function(){
x<-1
mapply(get,"x", MoreArgs = list(envir=environment()))
}
c()
x
1
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?
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.
This is because R uses lexical scoping, as opposed to dynamic scoping.
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
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
where environment(mapply)
equals asNamespace("base")
, the base namespace environment.
这篇关于R中的环境,应用和获取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!