这个问题可能看起来有点复杂,但让我烦恼了一段时间。这也只是出于好奇,因为我已经有了完成所需的方法,所以并不是很重要。
在R中,我需要一个函数来返回一个命名的列表对象,其中包括用户输入的所有参数和值。为此,我编写了以下代码(玩具示例):
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- frm
for (i in 1:length(frm))
parms[[i]] <- get(names(frm)[i])
return(parms)
}
所以当被问到:
> foo(b=0)
$a
[1] 1
$b
[1] 0
$h
[1] "coconut"
这个结果很完美。但是问题是,当我尝试使用lapply
来达到同样的目的,以便更加高效(和优雅),它并不按照我想要的方式工作:
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get)
names(parms) <- names(frm)
return(parms)
}
问题显然出在get
函数评估其第一个参数(变量名的字符字符串)的环境中。这一点我部分是从错误信息中知道的:
> foo(b=0)
Error in FUN(c("a", "b", "h")[[1L]], ...) : object 'a' not found
此外,因为在 .GlobalEnv
环境中存在名称正确的对象,所以 foo 函数会返回它们的值:
> a <- 100
> b <- -1
> h <- 'wallnut'
> foo(b=0)
$a
[1] 100
$b
[1] -1
$h
[1] "wallnut"
显然,默认情况下get
是在parent.frame()
中进行评估的,它搜索的对象位于.GlobalEnv
环境中,而不是当前函数的环境中。这很奇怪,因为第一版本的函数没有这种情况。
我尝试了许多选项来使函数get
在正确的环境中进行评估,但无法正确地实现(我尝试过pos=-2,0,1,2
和envir=NULL
作为选项)。
如果有人在环境方面比我知道得多,特别是在这种“奇怪”的情况下,我希望知道如何解决这个问题。
谢谢您的时间,
Juan
foo2
和foo3
有自己的形式参数,而不是foo
的话,那就更好了 :-) - Tommyenvr=sys.parent() + 1
,会有什么不同吗? - Juansys.frame(sys.parent(0))
,我认为environment()
更加明显。实际上,你可以用mget(names(frm), environment())
替换整行代码。 - hadleyas.list(environment())
替换整个函数。 - hadley