英文:
assertthat return the message from the current function when called in a nested manner
问题
让我通过一个例子来解释。
我有两个函数:
fun1 <- function(x) {
assertthat::assert_that(is.numeric(x), msg = '不是一个数字')
x
}
fun2 <- function(x) {
assertthat::assert_that(x > 10, msg = '数字不大于10')
x + 10
}
它们相互调用。
fun1(x = fun2(20))
#[1] 30
然而,如果fun2
失败,我会从fun1
得到消息。
fun1(x = fun2(2))
错误: 不是一个数字
我期望从fun2
本身得到消息,即'数字不大于10'
。
我知道我可以像下面这样分解函数调用来解决我的问题。
y <- fun2(20)
fun1(x = y)
但这只是一个简化的例子。在我的实际情况中,这样做是不可能的,也不是我想要的方式。
有什么想法吗?
英文:
Let me explain with the help of an example.
I have two functions :
fun1 <- function(x) {
assertthat::assert_that(is.numeric(x), msg = 'Not a number')
x
}
fun2 <- function(x) {
assertthat::assert_that(x > 10, msg = 'Number not greater than 10')
x + 10
}
They are called one into another.
fun1(x = fun2(20))
#[1] 30
However, if fun2
fails, I get message from fun1
.
fun1(x = fun2(2))
>Error: Not a number
I would expect to get message from fun2
itself which is 'Number not greater than 10'
.
How can I get that?
I know I can break down the function calls like below which will resolve my issue.
y <- fun2(20)
fun1(x = y)
but this is a simplified example. In my real case, it is not possible to do this nor do I want to do it in that way.
Any ideas?
答案1
得分: 1
以下是您要求的翻译部分:
我的理解是,assert_that()
将省略号 ...
传递给 see_if()
,在这个函数中,省略号被捕获并使用 eval(substitute(alist(...)))
。这可以防止在 fun2
中的错误被评估。错误对象从 fun2()
返回,然后在 fun1()
中的条件中检查,检查错误对象是否为 is.numeric
,但它不是,所以结果是预期的 'Not a number'
。
避免这种情况的一种方法是评估 fun2()
的结果。在您的帖子中,您已经展示了一种方法,通过使用中间对象。另一种方法是使用 eval(bquote())
早期评估 fun2()
的结果。在 bquote()
中使用 .()
来在错误对象被 see_if()
捕获之前早期评估 fun2()
。但我猜这不是您期望的解决方案。
fun1 <- function(x) {
eval(bquote(assertthat::assert_that(.(is.numeric(x)), msg = 'Not a number')))
x
}
fun2 <- function(x) {
assertthat::assert_that(x > 10, msg = 'Number not greater than 10')
x + 10
}
fun1(x = fun2(20))
#> [1] 30
fun1(x = fun2(5))
#> Error: Number not greater than 10
由于 assert_that
只是 stopifnot()
的一个可替代项,更简单的方法是只使用后者 - 错误消息并不那么糟糕:
fun1 <- function(x) {
stopifnot("Not a number" = is.numeric(x))
x
}
fun2 <- function(x) {
stopifnot('Number not greater than 10' = x > 10)
x + 10
}
fun1(x = fun2(20))
#> [1] 30
fun1(x = fun2(5))
#> Error in fun2(5): Number not greater than 10
创建于2023-02-27,使用 reprex 包 (v2.0.1)。
英文:
My understanding of the problem is that, assert_that()
passes the ellipsis ...
to see_if()
and in this function the ellipsis is captured with eval(substitute(alist(...))
. This prevents the error in fun2
to be evaluated. The error object is returned from fun2()
and then checked against the condition in fun1()
, checking whether the error object is.numeric
which it isn't so the result is as expected 'Not a number'
.
One way to avoid this is to evaluate the result of fun2()
. In your post you have shown one way, by using an intermediate object. Another way is to evalute the result of fun2()
early using eval(bquote())
. Below we use .()
inside bquote()
to evaluate fun2()
early before the error object that is return is captured by see_if()
. But I guess this is not your desired solution.
fun1 <- function(x) {
eval(bquote(assertthat::assert_that(.(is.numeric(x)), msg = 'Not a number')))
x
}
fun2 <- function(x) {
assertthat::assert_that(x > 10, msg = 'Number not greater than 10')
x + 10
}
fun1(x = fun2(20))
#> [1] 30
fun1(x = fun2(5))
#> Error: Number not greater than 10
Since assert_that
is just a drop-in replacement for stopifnot()
the easier approach is to just use the latter - the error messages are not that bad:
fun1 <- function(x) {
stopifnot("Not a number" = is.numeric(x))
x
}
fun2 <- function(x) {
stopifnot('Number not greater than 10' = x > 10)
x + 10
}
fun1(x = fun2(20))
#> [1] 30
fun1(x = fun2(5))
#> Error in fun2(5): Number not greater than 10
<sup>Created on 2023-02-27 by the reprex package (v2.0.1)</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论