Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 如何将警告和错误保存为函数的输出?_R_Error Handling_Try Catch - Fatal编程技术网

R 如何将警告和错误保存为函数的输出?

R 如何将警告和错误保存为函数的输出?,r,error-handling,try-catch,R,Error Handling,Try Catch,我正在使用lappy对大量项目运行一个复杂的函数,并且我希望将每个项目(如果有)的输出与产生的任何警告/错误一起保存,以便我可以知道哪个项目产生了哪个警告/错误 我找到了一种通过调用处理程序捕捉警告的方法。然而,我也需要捕捉错误。我可以通过将它包装在tryCatch(如下面的代码)中来完成,但是有更好的方法吗 catchToList <- function(expr) { val <- NULL myWarnings <- NULL wHandler <- f

我正在使用
lappy
对大量项目运行一个复杂的函数,并且我希望将每个项目(如果有)的输出与产生的任何警告/错误一起保存,以便我可以知道哪个项目产生了哪个警告/错误

我找到了一种通过调用处理程序捕捉警告的方法。然而,我也需要捕捉错误。我可以通过将它包装在
tryCatch
(如下面的代码)中来完成,但是有更好的方法吗

catchToList <- function(expr) {
  val <- NULL
  myWarnings <- NULL
  wHandler <- function(w) {
    myWarnings <<- c(myWarnings, w$message)
    invokeRestart("muffleWarning")
  }
  myError <- NULL
  eHandler <- function(e) {
    myError <<- e$message
    NULL
  }
  val <- tryCatch(withCallingHandlers(expr, warning = wHandler), error = eHandler)
  list(value = val, warnings = myWarnings, error=myError)
} 

这里有几个问题可以讨论
tryCatch
和错误处理,但我发现没有一个可以解决这个特定问题。请参阅和,以了解最相关的函数。

也许这与您的解决方案相同,但我编写了一个
工厂
,将普通的旧函数转换为捕获其值、错误和警告的函数,以便

test <- function(i)
    switch(i, "1"=stop("oops"), "2"={ warning("hmm"); i }, i)
res <- lapply(1:3, factory(test))
以及一些处理结果列表的助手

.has <- function(x, what)
    !sapply(lapply(x, "[[", what), is.null)
hasWarning <- function(x) .has(x, "warn")
hasError <- function(x) .has(x, "err")
isClean <- function(x) !(hasError(x) | hasWarning(x))
value <- function(x) sapply(x, "[[", 1)
cleanv <- function(x) sapply(x[isClean(x)], "[[", 1)
.has请尝试


它还捕获消息,输出到控制台,并确保所有内容都按照发生的顺序正确交错。

我已将Martins soulution()与您通过
演示(error.catching)
获得的R-help邮件列表中的内容合并

主要思想是保留警告/错误消息以及触发此问题的命令。

myTryCatch <- function(expr) {
  warn <- err <- NULL
  value <- withCallingHandlers(
    tryCatch(expr, error=function(e) {
      err <<- e
      NULL
    }), warning=function(w) {
      warn <<- w
      invokeRestart("muffleWarning")
    })
  list(value=value, warning=warn, error=err)
}
输出:

>myTryCatch(日志(1))

$value[1]0 $warning NULL $error NULL

>myTryCatch(日志(-1))

$value[1]NaN $warning $error NULL

>myTryCatch(日志(“a”))

$value NULL $warning NULL $error

我的回答(以及对Martin优秀代码的修改)的目的是,如果一切顺利,factory ed函数将返回预期的数据结构。如果遇到警告,则会将其附加到“工厂警告”属性下的结果。表的
setattr
函数用于允许与该包兼容。如果遇到错误,则结果是字符元素“工厂功能中发生错误”,并且
工厂错误
属性将携带错误消息

#' Catch errors and warnings and store them for subsequent evaluation
#'
#' Factory modified from a version written by Martin Morgan on Stack Overflow (see below).  
#' Factory generates a function which is appropriately wrapped by error handlers.  
#' If there are no errors and no warnings, the result is provided.  
#' If there are warnings but no errors, the result is provided with a warn attribute set.
#' If there are errors, the result retutrns is a list with the elements of warn and err.
#' This is a nice way to recover from a problems that may have occurred during loop evaluation or during cluster usage.
#' Check the references for additional related functions.
#' I have not included the other factory functions included in the original Stack Overflow answer because they did not play well with the return item as an S4 object.
#' @export
#' @param fun The function to be turned into a factory
#' @return The result of the function given to turn into a factory.  If this function was in error "An error as occurred" as a character element.  factory-error and factory-warning attributes may also be set as appropriate.
#' @references
#' \url{http://stackoverflow.com/questions/4948361/how-do-i-save-warnings-and-errors-as-output-from-a-function}
#' @author Martin Morgan; Modified by Russell S. Pierce
#' @examples 
#' f.log <- factory(log)
#' f.log("a")
#' f.as.numeric <- factory(as.numeric)
#' f.as.numeric(c("a","b",1))
factory <- function (fun) {
  errorOccurred <- FALSE
  library(data.table)
  function(...) {
    warn <- err <- NULL
    res <- withCallingHandlers(tryCatch(fun(...), error = function(e) {
      err <<- conditionMessage(e)
      errorOccurred <<- TRUE
      NULL
    }), warning = function(w) {
      warn <<- append(warn, conditionMessage(w))
      invokeRestart("muffleWarning")
    })
    if (errorOccurred) {
      res <- "An error occurred in the factory function"
    } 

    if (is.character(warn)) {
      data.table::setattr(res,"factory-warning",warn)
    } else {
      data.table::setattr(res,"factory-warning",NULL) 
    }

    if (is.character(err)) {
      data.table::setattr(res,"factory-error",err)
    } else {
      data.table::setattr(res, "factory-error", NULL)
    }  
    return(res)
  }
}
#“捕获错误和警告,并将其存储以供后续评估
#'
#“工厂修改自Martin Morgan编写的关于堆栈溢出的版本(见下文)。
#'工厂生成一个由错误处理程序适当包装的函数。
#'如果没有错误和警告,则提供结果。
#'如果存在警告但没有错误,则结果将与警告属性集一起提供。
#'如果有错误,结果retutrns是一个包含warn和err元素的列表。
#'这是从循环评估或群集使用期间可能发生的问题中恢复的一种很好的方法。
#'检查其他相关函数的引用。
#'我没有包括原始堆栈溢出答案中包含的其他工厂函数,因为它们不能很好地将返回项作为S4对象使用。
#“@出口
#“@param fun将函数转换为工厂
#“@返回给定函数的结果以转换为工厂。如果此函数作为字符元素出现错误,“发生错误”。工厂错误和工厂警告属性也可以根据需要设置。
#“@参考资料
#'\url{http://stackoverflow.com/questions/4948361/how-do-i-save-warnings-and-errors-as-output-from-a-function}
#"作者马丁·摩根,;由罗素S.皮尔斯修改
#“@示例

#是的,同样的想法,但是更好!你考虑过把它包装成一个包裹吗?从我刚才看到的其他问题来看,其他人也会觉得这很有用。我有一个函数,它将调用存储在输出中。调用
factory
后,此调用将被更改,例如
fun(公式=…1,数据=…2,方法=“genetic”,比率=…4,print.level=0)
,其中
公式应为我的原始输入公式,但会被覆盖。有什么建议吗?@RomanLuštrik:我猜这是因为它实际上是在使一个新函数
有趣
,并用
调用它,而不是直接调用您的函数。我想知道我的
catchToList
功能是否有效,或者
工厂是否可以修改,也许可以使用
do.call
。如何复制?我非常喜欢下面@russellpierce使用属性捕获警告和错误消息的方法。因此,上面中间的
NULL
可以替换为
NA
“发生错误”
或类似内容,最后第二行替换为
attr(res,“warning”),当我尝试使用上面的
f.log时,它很好,但不捕获消息或打印。如果只使用一个函数就可以捕获所有4种主要输出类型,那就太好了。我之所以说main,是因为还有一些其他功能,比如绘图、写入剪贴板和写入文件。在某些情况下,我们也会注意捕捉这些。在本例中,或者一般情况下,有没有一种方法可以捕捉replay(t2)的输出<示例中的code>xf.log(10)打印“工厂函数中发生错误”,而不是像我预期的那样返回结果。但是,isClean()正确地报告为TRUE。那么你能得到返回值吗?或者这只是为了检查错误和警告?@ZakKeirn我无法用R3.5.1复制你的问题。请仔细检查复制和粘贴过程中是否有一点混乱。如果问题仍然存在,请共享有关执行环境的更多信息。R版本为3.5.2。我只是复制、粘贴,然后再次运行。如果我第一次运行
f.log(10)
,它将工作并返回一个值。然后,如果我运行
f.log(“a”)
,然后使用
f.log(10)
再次运行,它会返回“工厂函数中发生错误”。啊,这是一个很好的提示。关闭正在更新。我只想要你
library(evaluate)
test <- function(i)
    switch(i, "1"=stop("oops"), "2"={ warning("hmm"); i }, i)

t1 <- evaluate("test(1)")
t2 <- evaluate("test(2)")
t3 <- evaluate("test(3)")
replay(t1)
replay(t2)
replay(t3)
myTryCatch <- function(expr) {
  warn <- err <- NULL
  value <- withCallingHandlers(
    tryCatch(expr, error=function(e) {
      err <<- e
      NULL
    }), warning=function(w) {
      warn <<- w
      invokeRestart("muffleWarning")
    })
  list(value=value, warning=warn, error=err)
}
myTryCatch(log(1))
myTryCatch(log(-1))
myTryCatch(log("a"))
#' Catch errors and warnings and store them for subsequent evaluation
#'
#' Factory modified from a version written by Martin Morgan on Stack Overflow (see below).  
#' Factory generates a function which is appropriately wrapped by error handlers.  
#' If there are no errors and no warnings, the result is provided.  
#' If there are warnings but no errors, the result is provided with a warn attribute set.
#' If there are errors, the result retutrns is a list with the elements of warn and err.
#' This is a nice way to recover from a problems that may have occurred during loop evaluation or during cluster usage.
#' Check the references for additional related functions.
#' I have not included the other factory functions included in the original Stack Overflow answer because they did not play well with the return item as an S4 object.
#' @export
#' @param fun The function to be turned into a factory
#' @return The result of the function given to turn into a factory.  If this function was in error "An error as occurred" as a character element.  factory-error and factory-warning attributes may also be set as appropriate.
#' @references
#' \url{http://stackoverflow.com/questions/4948361/how-do-i-save-warnings-and-errors-as-output-from-a-function}
#' @author Martin Morgan; Modified by Russell S. Pierce
#' @examples 
#' f.log <- factory(log)
#' f.log("a")
#' f.as.numeric <- factory(as.numeric)
#' f.as.numeric(c("a","b",1))
factory <- function (fun) {
  errorOccurred <- FALSE
  library(data.table)
  function(...) {
    warn <- err <- NULL
    res <- withCallingHandlers(tryCatch(fun(...), error = function(e) {
      err <<- conditionMessage(e)
      errorOccurred <<- TRUE
      NULL
    }), warning = function(w) {
      warn <<- append(warn, conditionMessage(w))
      invokeRestart("muffleWarning")
    })
    if (errorOccurred) {
      res <- "An error occurred in the factory function"
    } 

    if (is.character(warn)) {
      data.table::setattr(res,"factory-warning",warn)
    } else {
      data.table::setattr(res,"factory-warning",NULL) 
    }

    if (is.character(err)) {
      data.table::setattr(res,"factory-error",err)
    } else {
      data.table::setattr(res, "factory-error", NULL)
    }  
    return(res)
  }
}
.has <- function(x, what) {
  !is.null(attr(x,what))
}
hasWarning <- function(x) .has(x, "factory-warning")
hasError <- function(x) .has(x, "factory-error")
isClean <- function(x) !(hasError(x) | hasWarning(x))