简体   繁体   English

从 R 中的函数中捕获警告并仍然获得它们的返回值?

[英]Catch warnings from functions in R and still get their return-value?

Within a function I'm calling another calculation-invensive foreign function, which triggers warnings in some situation, but also returns a value, which I'd like to evaluate, regardless whether warnings occurred or not.在一个函数中,我正在调用另一个计算密集型外部函数,该函数在某些情况下会触发警告,但也会返回一个值,我想评估该值,无论是否发生警告。

Additionally, if warnings or errors occurred, I want to catch the warning/error messages for further processing.此外,如果发生警告或错误,我想捕获警告/错误消息以进行进一步处理。

The following R code demonstrates my intention:下面的 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)
}

When errors occurr, the code ends up in the error-catch section, so it is obvious that I won't be able to get the return-value from hurz().发生错误时,代码会在错误捕获部分结束,因此很明显我将无法从 hurz() 获取返回值。

However, there seems to be no nice way to simultaneously get但是,似乎没有好的方法可以同时获得

  • the return-value of hurz() as well as hurz() 的返回值以及
  • the warning produced.产生的警告。

When calling laus(3) I get the following response:调用laus(3)我得到以下响应:

$value
[1] 12345

$error_text
[1] "No error."

On the other hand, when calling laus(NULL) I get:另一方面,当调用laus(NULL)我得到:

[1] 12345

$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf\n"

Of course calling hurz() wrapped with the suppressWarnings as shown above would be a really ugly hack and is no option, since hurz() performs very calculation-intensive work.当然,调用 hurz() 与如上所示的抑制警告一起将是一个非常丑陋的 hack 并且没有选择,因为 hurz() 执行非常计算密集型的工作。

Does anyone have a clue how to solve this issue in a nice way and how I can catch warnings AND still get the fuction's return-value in one go?有没有人知道如何以一种很好的方式解决这个问题,以及我如何捕捉警告并仍然一次性获得函数的返回值?

Borrowing some poorly documented R magic demonstrated in this post , I think the following revised laus() function will do the trick:借用在这篇文章中展示的一些记录不佳的 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)
}

Now I can call laus(3) and get:现在我可以调用laus(3)并得到:

$value
[1] 12345

$error_text
[1] "No error."

or laus(NULL) and get:laus(NULL)并得到:

$value
[1] 12345

$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf"

or laus(foo) and get:laus(foo)并得到:

$value
[1] NA

$error_text
[1] "ERROR: Error in hurz(x): object 'foo' not found"

Note the use of <<- in the warning function.注意在warning函数中使用<<- This searches the enclosing frames of the warning function and overwrites the error_text value in the environment of the anonymous function that calls hurz .这将搜索warning函数的封闭框架并覆盖调用hurz的匿名函数环境中的error_text值。

I had to use a debugger with a breakpoint in the warning function to figure out the enclosing frames.我不得不在warning函数中使用带有断点的调试器来找出封闭的帧。 If you don't understand environments and frames in R, just trust that using <<- in this context will overwrite that error_text variable that is initialized to "No error."如果您不了解 R 中的环境和框架,只需相信在此上下文中使用<<-将覆盖初始化为“无错误”的error_text变量。

To understand this code a bit better, realize that withCallingHandlers() is itself a stand-alone function.为了更好地理解这段代码,请意识到withCallingHandlers()本身就是一个独立的函数。 This is illustrated by the following variation of the function, which will trap and recover from warnings, but will NOT handle errors:函数的以下变体说明了这一点,它将捕获并从警告中恢复,但不会处理错误:

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)
}

The output from this function will be identical to the laus() function, unless there is an error.除非出现错误,否则此函数的输出将与laus()函数相同。 In the case of an error, it will simply fail and report the error, as would any other function that lacks a tryCatch .在出现错误的情况下,它只会失败并报告错误,就像任何其他缺少tryCatch函数tryCatch For instance, lausOnlyHandleWarnings(foo) yields:例如, lausOnlyHandleWarnings(foo)产生:

Error in hurz(x) : object 'foo' not found

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM