我正在尝试创建一个函数,该函数引用调用它的范围来创建唯一ID:
uniqueid <- function(name, envir = NULL) {
if(identical(envir, globalenv())) {
e = envir
} else if (is.null(envir)) {
e = parent.frame()
} else if (is.environment(envir)) {
e = envir
} else {
stop("given non-default argument \'envir\' is not an environment")
}
return(paste(sep = "",
sub('<environment: (.*)>', '\\1', capture.output(e)),
".",
name
)
)
}
我能做些什么才能让这项工作按照我认为应该有效的方式进行? R不断返回定义函数的范围,而不是返回它的评估位置:
hello <- new.env()
hello$env <- new.env()
eval(envir=hello$env, {
print(environment())
print(hello$env) #hello$env is an environment
print(hello) #hello is an environment
uniqueid('hi')
})
我试图让其中至少有一个匹配起来,但它似乎并不想工作。 R要么返回全局环境,要么为为函数调用的实例创建的临时帧/环境的不断变化的范围。 ID需要在多次调用之间重现,并且取决于环境。
我知道我可以通过环境,但我开始怀疑是否真的可以捕获调用者的环境。
答案 0 :(得分:3)
TL,DR:parent.frame()
不是parent.frame(environment())
; evalq
不是eval
。
parent.frame
将参数n
作为要返回的世代数,而不是environment()
调用的结果(这是一个环境)。如果您将其排除在parent.frame()
电话之外,那就很好。
此外,yoru示例代码并不像您期望的那样工作,因为在environment()
的调用中正在评估您的eval
命令,然后才将作为>的一部分进行评估 eval
。即你必须引用你的论点eval
。或者,使用evalq
而不是eval
。
E.g。
uniqueid <- function(name) {
print(parent.frame())
}
hello <- new.env()
hello$env <- new.env()
evalq(envir=hello$env, {
print(environment()) # prints hello$env
print(hello$env) # prints hello$env
print(hello) # prints hello
uniqueid('hi') # prints hello$env
})
E.g。这将获取环境ID并将其添加到name
:
uniqueid <- function(name) {
# GlobalEnv etc have names; hello doesn't
envName <- environmentName(parent.frame())
# get the environment ID from the parent.frame() output if no name
if (envName == "") {
p <- parent.frame()
envName <- sub('<environment: (.*)>', '\\1', capture.output(p))
}
return(paste(envName, name, sep=':'))
}
uniqueid('x') # R_GlobalEnv:x
print(hello) # <environment: 0x4641fa0>
evalq(envir=hello, uniqueid('x')) # "0x4641fa0:x"
print(hello$env) # <environment: 0x4640e60>
evalq(envir=hello$env, uniqueid('x')) # "0x4640e60:x"
答案 1 :(得分:2)
您的问题是eval()
期望某些内容未被评估。通过传入代码块{}
,您无法阻止评估。例如,考虑更简单的情况
a<-10
ee<-new.env()
ee$a<-5
eval(envir=ee, a)
# [1] 10
eval(envir=ee, {a})
# [1] 10
eval(envir=ee, quote(a))
# [1] 5
evalq(envir=ee, a)
# [1] 5
注意最后两个如何显式引用表达式,或使用evalq()
来引用表达式。这些允许评估延迟,直到在请求的环境中执行。
因此,如果您只是将eval()
更改为evalq()
,那么您应该没问题。