从 R 中的函数捕获警告并仍然获得它们的 return 值?
Catch warnings from functions in R and still get their return-value?
在一个函数中,我正在调用另一个计算复杂的外部函数,它在某些情况下会触发警告,但也会 returns 一个值,我想评估它,无论是否发生警告.
此外,如果出现警告或错误,我想捕获 warning/error 消息以进行进一步处理。
以下 R 代码演示了我的意图:
hurz <- function(x) {
# HINT: max(x) triggers a warning when x = NULL
max(x)
return(12345)
}
laus <- function(x) {
r <- tryCatch({
list(value = hurz(x), error_text = "No error.")
}, warning = function(e) {
error_text <- paste0("WARNING: ", e)
# ugly hack to get the result while still catching the warning
return(list(value = (suppressWarnings(hurz(5))), error_text = error_text))
}, error = function(e) {
error_text <- paste0("ERROR: ", e)
return(list(value = NA, error_text = error_text))
}, finally = {
}, quiet = TRUE)
return(r)
}
当发生错误时,代码会在错误捕获部分结束,因此很明显我无法从 hurz() 获取 return 值。
不过好像没有什么好的方法可以同时得到
- hurz() 的 return 值以及
- 产生警告。
调用 laus(3)
时,我得到以下响应:
$value
[1] 12345
$error_text
[1] "No error."
另一方面,当调用 laus(NULL)
我得到:
[1] 12345
$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf\n"
当然,如上所示调用用 suppressWarnings 包装的 hurz() 将是一个非常丑陋的 hack 并且是别无选择的,因为 hurz() 执行非常计算密集型的工作。
有没有人知道如何以一种好的方式解决这个问题,以及如何捕捉警告并仍然一次性获得函数的 return 值?
借用 this post 中演示的一些记录不完整的 R 魔术,我认为以下修改后的 laus()
函数可以解决问题:
laus <- function(x) {
r <-
tryCatch(
withCallingHandlers(
{
error_text <- "No error."
list(value = hurz(x), error_text = error_text)
},
warning = function(e) {
error_text <<- trimws(paste0("WARNING: ", e))
invokeRestart("muffleWarning")
}
),
error = function(e) {
return(list(value = NA, error_text = trimws(paste0("ERROR: ", e))))
},
finally = {
}
)
return(r)
}
现在我可以调用 laus(3)
并获得:
$value
[1] 12345
$error_text
[1] "No error."
或laus(NULL)
并得到:
$value
[1] 12345
$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf"
或laus(foo)
并得到:
$value
[1] NA
$error_text
[1] "ERROR: Error in hurz(x): object 'foo' not found"
注意 warning
函数中 <<-
的使用。这将搜索 warning
函数的封闭帧并覆盖调用 hurz
.
的匿名函数环境中的 error_text
值
我不得不在 warning
函数中使用带有断点的调试器来找出封闭的帧。如果您不了解 R 中的环境和框架,请相信在此上下文中使用 <<-
会覆盖初始化为“无错误”的 error_text
变量。
为了更好地理解这段代码,请认识到 withCallingHandlers()
本身就是一个独立的函数。函数的以下变体说明了这一点,它将捕获警告并从警告中恢复,但不会处理错误:
lausOnlyHandleWarnings <- function(x) {
r <-
withCallingHandlers(
{
error_text <- "No error."
list(value = hurz(x), error_text = error_text)
},
warning = function(e) {
error_text <<- trimws(paste0("WARNING: ", e))
invokeRestart("muffleWarning")
}
)
return(r)
}
此函数的输出将与 laus()
函数相同,除非出现错误。在出现错误的情况下,它将简单地失败并报告错误,就像任何其他缺少 tryCatch
的函数一样。例如,lausOnlyHandleWarnings(foo)
产生:
Error in hurz(x) : object 'foo' not found
在一个函数中,我正在调用另一个计算复杂的外部函数,它在某些情况下会触发警告,但也会 returns 一个值,我想评估它,无论是否发生警告.
此外,如果出现警告或错误,我想捕获 warning/error 消息以进行进一步处理。
以下 R 代码演示了我的意图:
hurz <- function(x) {
# HINT: max(x) triggers a warning when x = NULL
max(x)
return(12345)
}
laus <- function(x) {
r <- tryCatch({
list(value = hurz(x), error_text = "No error.")
}, warning = function(e) {
error_text <- paste0("WARNING: ", e)
# ugly hack to get the result while still catching the warning
return(list(value = (suppressWarnings(hurz(5))), error_text = error_text))
}, error = function(e) {
error_text <- paste0("ERROR: ", e)
return(list(value = NA, error_text = error_text))
}, finally = {
}, quiet = TRUE)
return(r)
}
当发生错误时,代码会在错误捕获部分结束,因此很明显我无法从 hurz() 获取 return 值。
不过好像没有什么好的方法可以同时得到
- hurz() 的 return 值以及
- 产生警告。
调用 laus(3)
时,我得到以下响应:
$value
[1] 12345
$error_text
[1] "No error."
另一方面,当调用 laus(NULL)
我得到:
[1] 12345
$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf\n"
当然,如上所示调用用 suppressWarnings 包装的 hurz() 将是一个非常丑陋的 hack 并且是别无选择的,因为 hurz() 执行非常计算密集型的工作。
有没有人知道如何以一种好的方式解决这个问题,以及如何捕捉警告并仍然一次性获得函数的 return 值?
借用 this post 中演示的一些记录不完整的 R 魔术,我认为以下修改后的 laus()
函数可以解决问题:
laus <- function(x) {
r <-
tryCatch(
withCallingHandlers(
{
error_text <- "No error."
list(value = hurz(x), error_text = error_text)
},
warning = function(e) {
error_text <<- trimws(paste0("WARNING: ", e))
invokeRestart("muffleWarning")
}
),
error = function(e) {
return(list(value = NA, error_text = trimws(paste0("ERROR: ", e))))
},
finally = {
}
)
return(r)
}
现在我可以调用 laus(3)
并获得:
$value
[1] 12345
$error_text
[1] "No error."
或laus(NULL)
并得到:
$value
[1] 12345
$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf"
或laus(foo)
并得到:
$value
[1] NA
$error_text
[1] "ERROR: Error in hurz(x): object 'foo' not found"
注意 warning
函数中 <<-
的使用。这将搜索 warning
函数的封闭帧并覆盖调用 hurz
.
error_text
值
我不得不在 warning
函数中使用带有断点的调试器来找出封闭的帧。如果您不了解 R 中的环境和框架,请相信在此上下文中使用 <<-
会覆盖初始化为“无错误”的 error_text
变量。
为了更好地理解这段代码,请认识到 withCallingHandlers()
本身就是一个独立的函数。函数的以下变体说明了这一点,它将捕获警告并从警告中恢复,但不会处理错误:
lausOnlyHandleWarnings <- function(x) {
r <-
withCallingHandlers(
{
error_text <- "No error."
list(value = hurz(x), error_text = error_text)
},
warning = function(e) {
error_text <<- trimws(paste0("WARNING: ", e))
invokeRestart("muffleWarning")
}
)
return(r)
}
此函数的输出将与 laus()
函数相同,除非出现错误。在出现错误的情况下,它将简单地失败并报告错误,就像任何其他缺少 tryCatch
的函数一样。例如,lausOnlyHandleWarnings(foo)
产生:
Error in hurz(x) : object 'foo' not found