【问题标题】:tryCatch does not catch an error if called though RScript如果通过 RScript 调用 tryCatch 不会捕获错误
【发布时间】:2012-07-08 18:15:09
【问题描述】:

我在 R 中遇到了一个奇怪的问题。

考虑以下代码(真实代码的真正简化版本,但仍然存在问题):

library(timeSeries)

tryCatch(
{
  specificWeekDay <- 2

  currTs <- timeSeries(c(1,2),c('2012-01-01','2012-01-02'),
                       format='%Y-%m-%d',units='A')
  # just 2 dates out of range
  start <- time(currTs)[2]+100*24*3600
  end <- time(currTs)[2]+110*24*3600

  # this line returns an empty timeSeries
  currTs <- window(currTs,start=start,end=end)

  message("Up to now, everything is OK")

  # this is the line with the uncatchable error
  currTs[!(as.POSIXlt(time(currTs))$wday %in% specificWeekDay),] <- NA

  message("I'm after the bugged line !")

},error=function(e){message(e)})

message("End")

当我在 RGui 中运行该代码时,我正确地得到以下输出:

到目前为止,一切正常
评估参数“i”时出错 为函数“[ 结束

相反,当我使用以下行通过 RScript(在 Windows 中)运行它时:

RScript.exe --vanilla "myscript.R"

我得到这个输出:

到目前为止,一切正常
执行中断

RScript 好像崩溃了……

知道原因吗?
这是 timeSeries 包错误,还是我做错了什么?
如果是后者,确保捕获所有错误的正确方法是什么?

提前致谢。


编辑:

这是一个较小的示例,它重现了不使用 timeSeries 包的问题。要对其进行测试,只需按上述方式运行即可:

library(methods)
# define a generic function
setGeneric("foo", 
           function(x, ...){standardGeneric("foo")})
# set a method for the generic function
setMethod("foo", signature("character"),
          function(x) {x})
tryCatch(
{
  foo("abc")
  foo(notExisting)
},error=function(e)print(e))

这似乎与泛型方法调度有关;当方法的参数导致错误时,调度程序无法找到该方法的签名并随之引发tryCatch 函数在通过 RScript 运行时似乎无法处理的异常。
奇怪的是,例如 print(notExisting) 不会发生这种情况;在这种情况下,异常会得到正确处理。

关于原因以及如何捕捉此类错误的任何想法?

注意:
我在 Windows 7 上使用 R-2.14.2

【问题讨论】:

    标签: r try-catch


    【解决方案1】:

    关于tryCatch()的信息[OP已经知道并使用但我没有注意到]

    我认为您错过了您的tryCatch() 没有对错误进行任何特殊处理,因此您以正常方式引发错误。在交互式使用中,会以通常的方式抛出和处理错误,但在非交互式会话中运行的脚本中的错误(例如 Rscript)将中止正在运行的脚本。

    tryCatch() 是一个复杂的函数,它允许在 R 中捕获和处理各种事件,而不仅仅是错误。然而,默认情况下,它被设置为模仿标准 R 错误处理过程;基本上允许 R 抛出和报告错误。如果您希望 R 执行基本行为以外的任何操作,则需要为错误添加特定的处理程序:

    > e <- simpleError("test error")
    > tryCatch(foo, error = function(e) e,
    +          finally = writeLines("There was a problem!"))
    There was a problem!
    <simpleError in doTryCatch(return(expr), name, parentenv, handler): object 'foo'
    not found>
    

    我建议您更详细地阅读 ?tryCatch 以更好地了解它的作用。

    另一种方法是使用try()。要修改您的脚本,我会这样做:

    # this is the line with the uncatchable error
    tried <- try(currTs[!(as.POSIXlt(time(currTs))$wday %in% specificWeekDay),] <- NA,
                 silent = TRUE)
    if(inherits(tried, "try-error")) {
        writeLines("There was an error!")
    } else {
        writeLines("Everything worked fine!")
    }
    

    关键是保存从try() 返回的对象,以便您可以测试该类,并让try() 静默运行。考虑差异:

    > bar <- try(foo)
    Error in try(foo) : object 'foo' not found
    > bar <- try(foo, silent = TRUE)
    > class(bar)
    [1] "try-error"
    

    请注意,在上面的第一次调用中,错误被捕获作为消息报告。第二种,没有报道。在这两种情况下,都会返回 "try-error" 类的对象。

    在内部,try() 被编写为对 tryCatch() 的单个调用,它为错误处理程序设置了一个自定义函数,该函数将错误作为消息报告并设置返回的对象。您可能希望研究 try() 的 R 代码作为使用 tryCatch() 的另一个示例。

    【讨论】:

    • 感谢您的回答,但我不认为我完全了解您。我的意思是,我已经为错误设置了一个处理程序(即 error=function(e){message(e)})所以,当遇到错误时,它应该调用这个函数并停止表达式的评估,对吧? (实际上确实如此,不包括这种特殊情况)。也许我遇到的异常不是从错误类继承的?
    • 道歉;我完全错过了您代码中的那一行。即使我用我的答案中的simpleError 替换您的错误位,我也可以重现这一点。有趣的是,如果您将try 替换为tryCatch,注释掉调用的error = .... 部分并添加silent = TRUE,您的脚本确实可以通过source() 在运行的R 中正常工作会话并通过Rscript。必须是特定于您正在做的事情;我根据我的答案尝试了一个示例(但没有使用您的示例),它与 RScript 配合得很好。我想知道timeSeries 是否正在做一些超出通常错误处理的事情?
    • 别担心 :) 关于我不知道的错误,我也开始认为 timeSeries 对错误做了一些奇怪的事情......
    • 嗯,似乎是在as.POSIXlt.numeric() 中抛出的错误,但是任何人都猜测为什么要区别对待。
    【解决方案2】:

    问题在于实现 S4 方法分派的内部 C 代码尝试捕获和处理一些错误的方式以及在这种方法中如何处理非交互式情况。很快就会在 R-devel 和 R-patched 中找到解决方法。

    解决方法现在致力于 R-devel 和 R-patched。

    【讨论】:

    • 谢谢卢克!很高兴在 SO 上见到你。
    • 欢迎来到 Stack Overflow!感谢您为 R 核心团队所做的所有工作。
    • R-core 团队的直接回答:O 非常感谢卢克! :)
    • 有谁知道这是否已修复?我在 R bugzilla 中找不到错误报告?我在使用 R 2.15.0 的 Linux 上遇到了同样的错误。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-05-14
    • 2017-07-19
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 2012-12-10
    • 2021-04-07
    • 2015-08-20
    相关资源
    最近更新 更多