配置:
OS : Windows 10 (64 bits)
R version: 3.6.3
我正在学习 R,目前我正在阅读 R 中的环境。我正在做一些练习,我想出了一个我自己创建的示例,但似乎我仍然无法解释和理解在 R 中正确查找对象的概念。一般来说,到目前为止我所理解的(如果我错了,请纠正我)是,如果 R 在当前环境中找不到对象,它会按顺序调用所有现有的父环境。只是为了看看它在实践中如何工作,我创建了以下程序:
library(rlang)
library(envnames)
library(lobstr)
e1 <- env()
e2 <- new_environment(parent = e1)
e3 <- new_environment(parent = e2)
e4 <- new_environment(parent = e3)
e5 <- new_environment(parent = e4)
e6 <- new_environment(parent = e5)
e7 <- new_environment(parent = e6)
e8 <- new_environment(parent = e7)
e9<- new_environment(parent = e8)
e10 <- new_environment(parent = e9)
e4$testvar <- 1200
e10$testfun <- function(x) {
print(envnames::environment_name(caller_env()))
return (testvar)
}
这是我如何通过选择 e10 作为调用者环境来运行上述程序
with(data = e10, expr = e10$testfun())
鉴于 testvar 是在环境 e4 中定义的,并且 e4 是 e10 的祖先,我预计为了找到 testvar 的值,R 在父树中从 e10 上升到 e4。但程序因以下错误而停止:
Error in e10$testfun() (from #3) : object 'testvar' not found
你能告诉我我误解了什么吗?我使用 with(data = e10, ...)
的事实不应该意味着用于函数调用的环境是 e10?
最佳答案
所以,这是一个异常微妙的问题。您需要在这里考虑两种相关类型的环境,绑定(bind)环境,或者与您的函数绑定(bind)的环境,以及封闭环境,或者创建函数的环境。在本例中,绑定(bind)环境是 e10
,但封闭环境是全局环境。来自 Hadley Wickham's Advanced R :
The enclosing environment belongs to the function, and never changes, even if the function is moved to a different environment. The enclosing environment determines how the function finds values; the binding environments determine how we find the function.
考虑以下内容(在执行您提供的代码后执行)来演示这一点:
eval(expression(testfun()), envir = e10)
# [1] "e10"
# Error in testfun() : object 'testvar' not found
testvar <- 600
eval(expression(testfun()), envir = e10)
# [1] "e10"
# [1] 600
此外,现在考虑:
eval(envir = e10, expr = expression(
testfun2 <- function(x) {
print(envnames::environment_name(caller_env()))
return (testvar)
}
))
eval(expression(testfun2()), envir = e10)
# [1] "e10"
# [1] 1200
我希望这能澄清这个问题。
更新:确定封闭和绑定(bind)环境
那么我们如何确定诸如 testfun()
之类的函数的绑定(bind)和封闭环境?
如G. Grothendieck's answer shows ,environment()
函数为您提供函数的封闭环境:
environment(e10$testfun)
# <environment: R_GlobalEnv>
据我所知,基础 R 中没有一个简单的函数可以为您提供函数的绑定(bind)环境。如果您要查找的函数位于父环境中,则可以使用 pryr::where()
:
pryr::where("mean")
# <environment: base>
(有一个base
函数用于查看函数是否在环境中,exists()
和pryr::where()
使用它。但是,它不会通过像 where()
这样的父环境进行递归。)
但是,如果您必须搜索子环境,据我所知,没有这样的功能。但是,模拟一个似乎很简单:
get_binding_environments <- function(fname) {
## First we need to find all the child environments to search through.
## We don't want to start from the execution environment;
## we probably want to start from the calling environment,
## but you may want to change this to the global environment.
e <- parent.frame()
## We want to get all of the environments we've created
objects <- mget(ls(envir = e), envir = e)
environments <- objects[sapply(objects, is.environment)]
## Then we use exists() to see if the function has a binding in any of them
contains_f <- sapply(environments, function(E) exists(fname, where = E))
return(unique(environments[contains_f]))
}
get_binding_environments("testfun")
# [[1]]
# <environment: 0x55f865406518>
e10
# <environment: 0x55f865406518>
关于r - 为什么 R 不在提供的环境父树中查找指定的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61568068/