我正在研究R中的“环境”概念。
现在我知道emptyenv()
是所有环境的父级,并且没有父级,但是有没有办法列出当前R会话中的所有环境,或者说emptyenv()
的子级?
答案 0 :(得分:1)
我的解决方案是递归地寻找环境。我们可以这样做,因为必须在可见/已知位置创建附加/新环境。不过,可能还有一些较小的边缘情况,例如函数或 R6 类中的环境:
fun <- function() {
ee <- new.env()
fun2 <- function() {
eee <- new.env()
}
return(1)
}
另一件事是抓住例如函数体的环境,在 {} 内。它将在函数评估而不是创建期间创建。这几乎是不可能的。
我要求对象识别为环境 - is.environment
和 inherits(e, "environment")
。后一种条件保护我们免受诸如 ggproto
加载了 ggplot2
之类的对象的侵害。
set.seed(1234)
# New environments - x7
#######################
eval(quote(ee <- new.env(parent = baseenv())))
eval(quote(ee1 <- new.env(parent = baseenv())), envir = ee)
ee2 <- new.env()
ee3 <- new.env(parent = ee2)
eval(quote(ee4 <- new.env(parent = baseenv())), envir = ee3)
eval(quote(ee5 <- new.env()), envir = baseenv())
eval(quote(ee6 <- new.env(parent = .GlobalEnv)), envir = ee3)
#######################
subenv <- function(env) {
envs <- unique(Filter(function(e) is.environment(e) && inherits(e, "environment"), lapply(ls(env), function(x) get(x, env))))
unlist(append(envs, lapply(envs, subenv)))
}
search_all = function() {
ees <- unlist(append(.GlobalEnv, rlang::env_parents(.GlobalEnv)))
unname(unlist(lapply(ees, subenv)))
}
library(ggplot2)
search_all()
结果:
> search_all()
[[1]]
<environment: 0x7f9c75e66e10>
[[2]]
<environment: 0x7f9c75e65600>
[[3]]
<environment: 0x7f9c75e68e80>
[[4]]
<environment: 0x7f9c75e65e88>
[[5]]
<environment: 0x7f9c75e67ec0>
[[6]]
<environment: 0x7f9c75e6df38>
[[7]]
<environment: 0x7f9c75e6ef30>
编辑:
此功能可用于最大化环境可见性。
new.env <- function(...) {
ee <- base::new.env(...)
if(!identical(parent.frame(), .GlobalEnv)) {
assign(paste0("env_", data.table::address(ee)), ee, envir = .GlobalEnv)
}
ee
}
不幸的是,当某些包被构建时,默认情况下它将使用 base::new.env。甚至 assignInNamespace
在这里也可能不尽如人意。
答案 1 :(得分:0)
唯一的方法是列出会话中的所有对象,并将其子集列出为环境对象,这在R代码中是不可能的。
您可以通过递归搜索在全局环境中的所有内容以及其中对象所引用的环境(例如,每个函数和公式都引用一个环境)中列出大多数对象,并继续其父环境等但是,这并不能解决所有问题,因为程序包可以从其C代码中创建无法直接从R代码访问的对象。
如果您愿意编写棘手的低级C代码,则必须像垃圾收集器那样在R的堆中进行相同的搜索。堆包含每个对象,但是直到发生垃圾回收之前,它才真正区分已删除的对象。因此,您可能会发现一些真正无法访问的环境。