我有一个函数f
,它计算调用它的环境的摘要。在这个简单的例子中,它只是总结了所有找到的对象。
f <- function(){
x <- ls(parent.frame())
sum(sapply(x, get, envir=parent.frame()))
}
g <- function(x = 7, y){
z <- 3
f()
}
但是,如果从缺少参数的函数内调用,则会抛出错误。
R> g(y = 34)
[1] 44
R> g()
Error in FUN(c("x", "y", "z")[[2L]], ...) :
argument "y" is missing, with no default
为了恰当地处理它,我需要一种方法来告诉f
,y
或g
环境中的其他任意对象是g
的参数1}}在这种情况下,如果它丢失了。
尝试不同的解决方案
debug(f)
g()
当然missing(y)
不起作用,因为y
不是f
的参数。更改评估missing
的环境也不起作用,因为我们仍处于调用堆栈的同一级别:
Browse[2]> eval(missing(y), parent.frame())
Error in missing(y) : 'missing' can only be used for arguments
Browse[2]> identical(sys.frames(), eval(sys.frames(), parent.frame()))
[1] TRUE
我能做的是确定y
是否是g
使用脏黑客的函数的参数
Browse[2]> eval(substitute(missing(a), list(a="x")), parent.frame())
[1] TRUE
Browse[2]> eval(substitute(missing(a), list(a="y")), parent.frame())
[1] TRUE
Browse[2]> eval(substitute(missing(a), list(a="z")), parent.frame())
[1] FALSE
为TRUE
和x
两个参数产生y
,而不是普通变量z
。将它与检查参数是否可以检索的tryCatch
组合将解决问题,但它非常脏:
is.argument <- eval(substitute(missing(a), list(a="y")), parent.frame())
if(is.argument){
tryCatch({
get("y", parent.frame())
FALSE
}, error = function(e) TRUE)
} else {
NA
}
此外,我无法弄清楚如何为任意参数定义is.argument
,而不是上面示例中明确声明的"y"
。
实际上,f
的目的是在运行时调试g
。我可以打电话给
R> debug(g)
R> g()
逐步执行它并使用f
检查对象的状态,或者我可能设置options(error=recover)
并发现自己调试g
如果它产生了错误。在这两种情况下都应该有一个明确定义的调用堆栈,所以我想我的基本问题是它是否可以在不同的层次上查询,与帧堆栈类似(用sys.frames()
访问)。我必须承认,这对我来说是深水。
将f
视为我自己的ls.str
调整版,可以像这样使用:
Browse[2]> ls.str() # Inside g()
x : num 7
y : <missing>
在ls.str
和utils:::print.ls_str
进行了一些挖掘后,我发现它完成了同样的任务
for (nam in x) {
cat(nam, ": ")
o <- tryCatch(get(nam, envir = E, mode = M), error = function(e) e)
if (inherits(o, "error")) {
cat(if (length(grep("missing|not found", o$message)))
"<missing>"
else o$message, "\n", sep = "")
} else {
strO <- function(...) str(o, ...)
do.call(strO, strargs, quote = is.call(o) || is.symbol(o))
}
}
除非有正确的方法,否则我会做出类似的黑客攻击。
答案 0 :(得分:3)
缺失参数的值在由称为“空符号”的奇怪对象与环境相关联的pairlist中表示。事实证明,至少在目前,“空符号”也是通过调用quote(expr=)
返回的。 (See here用于讨论空符号。)
函数ls_safe()
使用这两个事实来实现缺失的替代测试。它返回由其pos
参数指定的环境中存在的非缺失变量的字符向量。
ls_safe <- function(pos=1) {
## Capture the parent environment's frame as a list
ll <- as.list(parent.frame(pos))
## Check for "missing" variables
ii <- sapply(ll, function(X) identical(X, quote(expr=)))
names(ll)[!ii]
}
## Then just use ls_safe() in place of ls()
f <- function(){
x <- ls_safe(pos=2)
sum(sapply(x, get, envir=parent.frame()))
}
g <- function(x = 7, y){
z <- 3
f()
}
g(99)
## [1] 102
g(99, 1000)
## [1] 1102
答案 1 :(得分:1)
我遇到了同样的问题:想要一个检查参数是否缺失的函数。我还首先尝试了eval
为基础的想法,即使缺少变量,也总是给我FALSE
。
Josh上面提供了一个解决方案,但它太具体了。我想要的是一个整洁的检查器功能,我可以添加到我的功能,以便他们检查必要的变量中的缺失并抛出信息错误。这是我的解决方案:
check_missing = function(var_names, error_msg = "[VAR] was missing! Please supply the input and try again.") {
#parent.frame as list
pf = as.list(parent.frame())
#check each if missing
for (name in var_names) {
#is it there at all?
if (!name %in% names(pf)) {
stop(name + " is not even found in the parent.frame! Check the variable names!", call. = F)
}
#check if missing
if (are_equal(pf[[name]], quote(expr = ))) {
stop(str_replace(error_msg, pattern = "\\[VAR\\]", name), call. = F)
}
}
#all fine
return(invisible(NULL))
}
要测试它,请使用:
test_func = function(y) {
check_missing("y")
print("OK")
}
测试它:
test_func(y = )
# Error: y was missing! Please supply the input and try again.
# Called from: check_missing("y")
test_func(y = "k")
# [1] "OK"
我不满意的其余事情是该错误有错误的“来自”消息。它返回检查器函数本身,但如果返回父函数,它将提供更多信息。我不知道这是否可以解决。
希望这对某人有用。