Is there a "non-Internal" way to get the caller's name, as the function stop
does?
是否有一种“非内部”的方式来获取调用者的名字,就像函数stop所做的那样?
The idea is that I have a small function that checks the inputs and halts execution if some condition is not met. This function is called by several others, that use the same validation code. If the input is invalid, the caller's environment is dumped (so I can see arguments passed to the function), and execution halts.
其思想是,我有一个小函数来检查输入,如果不满足某些条件,就停止执行。这个函数被其他几个使用相同验证代码的函数调用。如果输入无效,调用者的环境被转储(因此我可以看到传递给函数的参数),执行停止。
Simplified example:
简化的例子:
check <- function(x)
{
if(x<0)
{
print(as.list(parent.frame()))
evalq(stop("invalid input."), parent.frame())
}
}
test <- function(x, y)
{
check(x)
}
I thought that evaluating the expression quote(stop("blah"))
in the caller's environment would make it show the caller's name. However, the result is the following:
我认为在调用者的环境中计算表达式引号(stop(“blah”)会使它显示调用者的名字。但是,结果如下:
test(-1, 2)
# $x
# [1] -1
#
# $y
# [1] 2
#
# Error in eval(substitute(expr), envir, enclos) : invalid input.
And this doesn't change if I use parent.frame(n)
with n>1
in evalq
.
如果我在evalq中使用n>1的parent.frame(n),这个不会改变。
So here is the question, actually two questions: 1. Is there a way to get the name of the function that created an environment (assuming it was created as such)? 2. Why the workaround above fails?
这是问题,实际上有两个问题:1。是否有一种方法可以获得创建环境的函数的名称(假设它是这样创建的)?2。为什么上面的解决方案失败了?
EDIT: I said the workaround above fails because I wanted the error message to appear as
编辑:我说上面的解决方案失败了,因为我希望错误消息显示为
Error in test(x, y) : invalid input.
as if the stop
statement were a part of test
body. So question 2 can be restated as: 2': Why didn't the evaluation of stop("invalid input.")
capture the caller's name, considering it was evaluated in the environment of the caller?
好像停止语句是测试主体的一部分。所以问题2可以重新表述为:2’:为什么停止(“无效输入”)的评估没有捕获调用者的名字,因为它是在调用者的环境中评估的?
5 个解决方案
#1
14
See ?match.call
. For example:
看到了什么? match.call。例如:
foo <- function() {
match.call()[[1]]
}
foo()
as.character(foo())
which produces
生产
> foo()
foo
>
> as.character(foo())
[1] "foo"
A simplified version of your code is
您的代码的简化版本是
check <- function(x) {
match.call()[[1]]
}
test <- function(y) {
check(y)
}
giving
给
> test(2)
check
> as.character(test(2))
[1] "check"
Note match.call()
works via the use of sys.call()
(actually it calls sys.call(sys.parent())
) when called as I did above with no arguments. So you may wish to consult ?sys.call
too.
注意match.call()通过使用sys.call()(实际上它在调用sys.call(sys.parent())时工作,正如我在上面所做的那样,没有参数。所以你可以咨询一下?调用。
#2
11
Thanks @GavinSimpson and @RicardoSporta, but I've figured it out. I'll post an answer in case somebody searches for this in SO.
谢谢@GavinSimpson和@RicardoSporta,但我已经算出来了。如果有人在SO中搜索这个,我会发布一个答案。
The name of the function that generated the current call can be retrieved by
可以检索生成当前调用的函数的名称
deparse(sys.calls()[[sys.nframe()-1]])
This returns a string that contains not only the name of the function, but the entire call object. The name alone can be retrieve by subsetting sys.calls()[[sys.nframe()-1]]
before deparsing.
它返回的字符串不仅包含函数的名称,还包含整个call对象。在离开之前,可以通过子设置sys.calls()[[sys.nframe()-1]]来检索单独的名称。
I wanted this because I wrote a function that checks the arguments and halts execution in case of an error. But I wanted this function to (i) dump the environment and (ii) show name of the function one level above in the execution stack. (i) is easy, but I was stuck in (ii).
我需要这样做,因为我编写了一个函数来检查参数,并在出现错误时停止执行。但是我希望这个函数(I)转储环境,(ii)在执行堆栈中显示上面一层的函数名。(我)很容易,但我被困住了。
As for the second question in my post, this is what happens: the expression stop("invalid input")
is evaluated in the environment of the test
function, but this is not the same thing as if the expression was part of test
's body, because the execution stack is different in this 2 scenarios. In the latter case, stop
has only test
above it, but in the first, it has eval
, check
and then test
upwards. The execution stack, returned by sys.calls()
is not the same thing as the enclosing environments. This is what may cause confusion.
至于第二个问题在我的帖子,这是会发生什么:表达式停止(“无效的输入”)是评价环境的测试函数,但这并不是一样的,如果表达式是测试的身体的一部分,因为这个2的执行堆栈不同场景。在后一种情况下,stop仅对其进行测试,但在第一种情况下,它具有eval, check,然后向上测试。sys.calls()返回的执行堆栈与封闭环境不同。这可能会引起混乱。
#3
6
For the record, as Hadley has suggested, you can use sys.call()
. For example:
对于记录,正如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
#4
3
Question #1 is answered by Gavin (use match.call
).
问题1由Gavin回答(使用match.call)。
However, based on what you are describing, you should also look at traceback()
, the output of which you can pass to other functions.
但是,根据您所描述的内容,您还应该查看traceback(),您可以将其输出传递给其他函数。
As for Question #2:
It isn't failing, but working exactly as expected. The error you are seeing is not an error in the true sense, but rather the error from your stop(.)
function.
它不是失败,而是按照预期工作。您看到的错误不是真正意义上的错误,而是来自stop(.)函数的错误。
If you look at print(evalq)
, you will see that it in turn calls eval(substitute(expr), envir, enclos))
where expr
is your stop("invalid input.")
如果您查看print(evalq),您将看到它反过来调用eval(substitute(expr)、envir、enclos),而expr是您的stop(“无效输入”)。
The correct workaround is to use one more level of quoting
evalq(quote(stop("invalid input.")))
# stop("invalid input.")
#5
0
To get the function name of the function above, you can simply use:
要获得上述函数的函数名,只需使用:
gsub(pattern="^([A-Za-z0-9]+)(\\({1})(.*)(\\){1})$",replacement="\\1",x=deparse(sys.call(-1)))
#1
14
See ?match.call
. For example:
看到了什么? match.call。例如:
foo <- function() {
match.call()[[1]]
}
foo()
as.character(foo())
which produces
生产
> foo()
foo
>
> as.character(foo())
[1] "foo"
A simplified version of your code is
您的代码的简化版本是
check <- function(x) {
match.call()[[1]]
}
test <- function(y) {
check(y)
}
giving
给
> test(2)
check
> as.character(test(2))
[1] "check"
Note match.call()
works via the use of sys.call()
(actually it calls sys.call(sys.parent())
) when called as I did above with no arguments. So you may wish to consult ?sys.call
too.
注意match.call()通过使用sys.call()(实际上它在调用sys.call(sys.parent())时工作,正如我在上面所做的那样,没有参数。所以你可以咨询一下?调用。
#2
11
Thanks @GavinSimpson and @RicardoSporta, but I've figured it out. I'll post an answer in case somebody searches for this in SO.
谢谢@GavinSimpson和@RicardoSporta,但我已经算出来了。如果有人在SO中搜索这个,我会发布一个答案。
The name of the function that generated the current call can be retrieved by
可以检索生成当前调用的函数的名称
deparse(sys.calls()[[sys.nframe()-1]])
This returns a string that contains not only the name of the function, but the entire call object. The name alone can be retrieve by subsetting sys.calls()[[sys.nframe()-1]]
before deparsing.
它返回的字符串不仅包含函数的名称,还包含整个call对象。在离开之前,可以通过子设置sys.calls()[[sys.nframe()-1]]来检索单独的名称。
I wanted this because I wrote a function that checks the arguments and halts execution in case of an error. But I wanted this function to (i) dump the environment and (ii) show name of the function one level above in the execution stack. (i) is easy, but I was stuck in (ii).
我需要这样做,因为我编写了一个函数来检查参数,并在出现错误时停止执行。但是我希望这个函数(I)转储环境,(ii)在执行堆栈中显示上面一层的函数名。(我)很容易,但我被困住了。
As for the second question in my post, this is what happens: the expression stop("invalid input")
is evaluated in the environment of the test
function, but this is not the same thing as if the expression was part of test
's body, because the execution stack is different in this 2 scenarios. In the latter case, stop
has only test
above it, but in the first, it has eval
, check
and then test
upwards. The execution stack, returned by sys.calls()
is not the same thing as the enclosing environments. This is what may cause confusion.
至于第二个问题在我的帖子,这是会发生什么:表达式停止(“无效的输入”)是评价环境的测试函数,但这并不是一样的,如果表达式是测试的身体的一部分,因为这个2的执行堆栈不同场景。在后一种情况下,stop仅对其进行测试,但在第一种情况下,它具有eval, check,然后向上测试。sys.calls()返回的执行堆栈与封闭环境不同。这可能会引起混乱。
#3
6
For the record, as Hadley has suggested, you can use sys.call()
. For example:
对于记录,正如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
#4
3
Question #1 is answered by Gavin (use match.call
).
问题1由Gavin回答(使用match.call)。
However, based on what you are describing, you should also look at traceback()
, the output of which you can pass to other functions.
但是,根据您所描述的内容,您还应该查看traceback(),您可以将其输出传递给其他函数。
As for Question #2:
It isn't failing, but working exactly as expected. The error you are seeing is not an error in the true sense, but rather the error from your stop(.)
function.
它不是失败,而是按照预期工作。您看到的错误不是真正意义上的错误,而是来自stop(.)函数的错误。
If you look at print(evalq)
, you will see that it in turn calls eval(substitute(expr), envir, enclos))
where expr
is your stop("invalid input.")
如果您查看print(evalq),您将看到它反过来调用eval(substitute(expr)、envir、enclos),而expr是您的stop(“无效输入”)。
The correct workaround is to use one more level of quoting
evalq(quote(stop("invalid input.")))
# stop("invalid input.")
#5
0
To get the function name of the function above, you can simply use:
要获得上述函数的函数名,只需使用:
gsub(pattern="^([A-Za-z0-9]+)(\\({1})(.*)(\\){1})$",replacement="\\1",x=deparse(sys.call(-1)))