【问题标题】:Advanced error handling高级错误处理
【发布时间】:2013-02-28 01:42:08
【问题描述】:

我最近发布了this question,幸好有人指向withRestarts(),这对我来说似乎非常棒且强大:-) 现在我渴望更详细地了解 R 的错误处理能力。

实际问题

  1. simpleCondition() 的推荐用法是什么?以前从未使用过它,但我认为它可能对设计实际上是“真实”条件的自定义错误和警告很有用。它是否可以用于构建一个包含特定处理程序可用的特定条件的数据库?
  2. 有没有办法“冻结”整个 R 工作区的某个状态并返回到它以在某个点重新开始计算?我知道save.image(),但是AFAIU,它不存储搜索路径的“状态”(search()searchpaths())。

对于那些感兴趣的人

两个代码示例

  1. 说明我当前使用withRestarts 依赖于这个blog post
  2. 尝试定义“自定义条件”

如果有任何关于如何做得更好的 cmets/建议,我将不胜感激 ;-)

示例 1

require("forecast")
autoArimaFailsafe <- function(
    x,
    warning=function(w, ...) {
        message("autoArimaFailsafe> warning:")
        message(w)
        invokeRestart("donothing")},
    error=function(e, ...) {
        message("autoArimaFailsafe> error:")
        message(e)
        invokeRestart("abort")}
) {
    withRestarts(
        out <- tryCatch(
           {
                expr <- expression(auto.arima(x=x))
                return(eval(expr))
           },
           warning=warning,
           error=error 
        ),
        donothing=function(...) {
            return(eval(expr))
        },
        abort=function(...) {
            message("aborting")
            return(NULL)
        }
    )    
}
data(AirPassengers)
autoArimaFailsafe(x=AirPassengers)
autoArimaFailsafe(x="a")

示例 2

require("forecast")
autoArimaFailsafe <- function(
    x,
    warning=function(w, ...) {
        message("autoArimaFailsafe> warning")
        invokeRestart("donothing")},
    error=function(e, ...) {
        message("autoArimaFailsafe> error")
        invokeRestart("abort")},
    condition=function(cond, ...) {
        out <- NULL
        message(cond)
        condmsg     <- conditionMessage(c=cond)
        condclass   <- class(cond)
        if (any(class(cond) == "simpleWarning")) {
            out <- warning(w=cond)
        } else if (any(class(cond) == "simpleError")) {
            out <- error(e=cond)
        } else if (any(class(cond) == "simpleCondition")) {
            if (condmsg == "invalid class: character") {
                out <- invokeRestart("forcedefault")
            }
        }
        return(out)
    }
) {
    withRestarts(
        out <- tryCatch(
           {
                expr <- expression(auto.arima(x=x))
                if (class(x) == "character") {
                    expr <- signalCondition(
                        simpleCondition("invalid class: character", 
                            call=as.call(expr))
                    )
                }
                return(eval(expr))
           },
           condition=condition
        ),
        donothing=function(...) {return(eval(expr))},
        abort=function(...) {
            message("aborting")
            return(NULL)
        },
        forcedefault=function(...) {
            data(AirPassengers)
            expr <- expression(auto.arima(x=AirPassengers))
            return(eval(expr))
        } 
    )
}
autoArimaFailsafe(x=AirPassengers)
autoArimaFailsafe(x=NULL)
autoArimaFailsafe(x="a")

【问题讨论】:

    标签: r error-handling conditional-statements application-restart


    【解决方案1】:

    This 帖子引用了 R 条件处理的灵感。

    对于 1.,我认为 simpleCondition 说明了如何构建自定义条件,例如。

     myCondition <-
        function(message, call=NULL, type=c("overflow", "underflow", "zero"))
    {
        type <- match.arg(type)             # only allowed types past here
        class <- c(type, "my", "condition")
        structure(list(message = as.character(message), call = call), 
            class = class)
    }
    

    是用于制作自定义条件的构造函数

    > myCondition("oops")
    <overflow: oops>
    > myCondition("oops", type="underflow")
    <underflow: oops>
    

    这些条件可以用在tryCatchwithCallingHandlers

    xx <- tryCatch({
        signalCondition(myCondition("oops", type="underflow"))
    }, underflow=function(e) {
        message("underflow: ", conditionMessage(e))
        NA # return value, assigned to xx
    })
    

    这些是 S3 类,因此可以具有线性层次结构 -- badworse 都是 error 的子类。

    myError <-
        function(message, call=NULL, type=c("bad", "worse"))
    {
        type <- match.arg(type)
        class <- c(type, "error", "condition")
        structure(list(message=as.character(message), call=call),
                  class=class)
    }
    

    也可能会创建一个错误,将“simpleError”S3 类扩展为cond &lt;- simpleError("oops"); class(cond) = c("myerr", class(cond)

    使用tryCatch,我们只需访问单个处理程序,第一个(在 ?tryCatch 中描述的意义上)匹配条件类

    tryCatch({
        stop(myError("oops", type="worse"))
    }, bad = function(e) {
        message("bad error: ", conditionMessage(e))
    }, worse = function(e) {
        message("worse error: ", conditionMessage(e))  # here's where we end up
    }, error=function(e) {
        message("error: ", conditionMessage(e))
    })
    

    使用withCallingHandlers,我们有机会访问多个处理程序,前提是我们不调用重新启动

    withCallingHandlers({
        stop(myError("oops", type="bad"))
    }, bad = function(e) {                             # here...
        message("bad error: ", conditionMessage(e))
    }, worse = function(e) {
        message("worse error: ", conditionMessage(e))
    }, error=function(e) {                             # ...and here...
        message("error: ", conditionMessage(e))
    })                                                 # ...and top-level 'error'
    
    withCallingHandlers({
        x <- 1
        warning(myError("oops", type="bad"))
        "OK"
    }, bad = function(e) {                     # here, but continue at the restart
        message("bad warning: ", conditionMessage(e))
        invokeRestart("muffleWarning")
    }, worse = function(e) {
        message("worse warning: ", conditionMessage(e))
    })
    

    我不太确定您的问题 2;我认为这是调用处理程序旨在解决的情况——一旦您调用重新启动,调用条件的整个帧都准备好等待继续。

    【讨论】:

    • 哇,很棒的答案!非常感谢
    猜你喜欢
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    相关资源
    最近更新 更多