是否有“非内部”方式来获取调用方的名称,正如函数stop
所做的那样?
我的想法是,我有一个小函数可以检查输入并在不满足某些条件时暂停执行。其他几个使用相同的验证代码调用此函数。如果输入无效,则转储调用者的环境(因此我可以看到传递给函数的参数),并且执行暂停。
简化示例:
check <- function(x)
{
if(x<0)
{
print(as.list(parent.frame()))
evalq(stop("invalid input."), parent.frame())
}
}
test <- function(x, y)
{
check(x)
}
我认为在调用者的环境中评估表达式quote(stop("blah"))
会使它显示调用者的名字。但结果如下:
test(-1, 2)
# $x
# [1] -1
#
# $y
# [1] 2
#
# Error in eval(substitute(expr), envir, enclos) : invalid input.
如果我在parent.frame(n)
n>1
使用evalq
,则不会改变。
所以这是问题,实际上有两个问题:1。有没有办法获得创建环境的函数的名称(假设它是这样创建的)? 2.为什么上面的解决方法失败了?
编辑:我说上面的解决方法失败了,因为我希望错误消息显示为
Error in test(x, y) : invalid input.
好像stop
语句是test
正文的一部分。所以问题2可以重述为:2':为什么stop("invalid input.")
的评估没有捕获调用者的名字,考虑到它是在调用者的环境中进行评估的?
答案 0 :(得分:17)
请参阅?match.call
。例如:
foo <- function() {
match.call()[[1]]
}
foo()
as.character(foo())
产生
> foo()
foo
>
> as.character(foo())
[1] "foo"
您的代码的简化版本是
check <- function(x) {
match.call()[[1]]
}
test <- function(y) {
check(y)
}
给
> test(2)
check
> as.character(test(2))
[1] "check"
注意match.call()
通过使用sys.call()
(实际上它调用sys.call(sys.parent())
)工作,因为我在上面调用时没有参数。所以您也可以咨询?sys.call
。
答案 1 :(得分:17)
感谢@GavinSimpson和@RicardoSporta,但我已经明白了。如果有人在SO中搜索,我会发一个答案。
可以通过
检索生成当前调用的函数的名称deparse(sys.calls()[[sys.nframe()-1]])
这将返回一个字符串,其中不仅包含函数的名称,还包含整个调用对象。只有名称可以通过在去除前的sys.calls()[[sys.nframe()-1]]
子集来检索。
我想要这个,因为我编写了一个函数来检查参数并在发生错误时暂停执行。但是我希望这个函数能够(i)转储环境,并且(ii)在执行堆栈中显示上面一级函数的名称。 (i)很容易,但我被困在(ii)。
至于我的帖子中的第二个问题,这是发生的事情:表达式stop("invalid input")
在test
函数的环境中进行评估,但这与表达式的表达方式不同test
主体的一部分,因为执行堆栈在这2个场景中是不同的。在后一种情况下,stop
仅高于test
,但在第一种情况下,它有eval
,check
,然后是test
。 sys.calls()
返回的执行堆栈与封闭环境不同。这可能会引起混淆。
答案 2 :(得分:6)
对于记录,正如Hadley建议的那样,您可以使用sys.call()
。例如:
funx = function(...) {
callingFun = as.list(sys.call(-1))[[1]]
calledFun = as.list(sys.call())[[1]]
message(paste(callingFun, " is calling ", calledFun, sep=""))
}
funy = function(...) {funx(...)}
> funy(a = 1, b = 2)
funy is calling funx
答案 3 :(得分:3)
问题#1由Gavin回答(使用match.call
)。
但是,根据您所描述的内容,您还应该查看traceback()
,其输出可以传递给其他函数。
它没有失败,但完全符合预期。您看到的错误不是真正意义上的错误,而是来自stop(.)
函数的错误。
如果您查看print(evalq)
,您会看到它依次调用eval(substitute(expr), envir, enclos))
,其中expr
是您的stop("invalid input.")
evalq(quote(stop("invalid input.")))
# stop("invalid input.")
答案 4 :(得分:0)
要获取上述功能的功能名称,您只需使用:
gsub(pattern="^([A-Za-z0-9]+)(\\({1})(.*)(\\){1})$",replacement="\\1",x=deparse(sys.call(-1)))