【问题标题】:Better error message for stopifnot?stopifnot 的更好的错误消息?
【发布时间】:2021-11-20 16:47:23
【问题描述】:

我正在使用stopifnot,我知道它只是返回不是TRUE 的第一个值。如果那是一些怪异的动态表达,那么不属于自定义功能的人就无法真正从中做出一些事情。所以我很想添加一个自定义错误消息。有什么建议吗?

Error: length(unique(nchar(check))) == 1 is not TRUE

基本上指出向量check 的元素长度不同。 有没有办法说:Error: Elements of your input vector do not have the same length!

【问题讨论】:

    标签: r


    【解决方案1】:

    使用stopif 语句:

    if(length(unique(nchar(check))) != 1) 
      stop("Error: Elements of your input vector do not have the same length!")
    

    请记住,stopifnot 可以方便地表示否定,因此您在if 中的条件需要是您的停止条件的否定。


    这是错误消息的样子:

    > check = c("x", "xx", "xxx")
    > if(length(unique(nchar(check))) != 1) 
    +   stop("Error: Elements of your input vector do not have the same length!")
    
    Error in eval(expr, envir, enclos) : 
      Error: Elements of your input vector do not have the same length!
    

    【讨论】:

    • 如果不好的话怎么办?我的意思是使用 if 是直观的解决方案。几乎所有语言都有它,甚至是英语。 stopifnot 有什么特殊用例吗?
    • @ran2 写stopifnot要快很多。
    • @ran2 stopifnot 的用例正是您目前使用它的目的。它非常直观。但它不会产生漂亮的错误消息。正如他们用英语所说的那样,用于课程的马匹。
    • @ran2. stopifnot 是检查输入的多个条件的快速方法。例如,如果你可以说stopifnot(A > 0, B < = 0, C == TRUE) 并确保当三个条件中的任何一个不满足时代码停止。
    【解决方案2】:

    可以将自定义消息作为标签添加到您的表达式中:

    stopifnot("Elements of your input vector do not have the same length!" =
      length(unique(nchar(check))) == 1)
    
    # Error: Elements of your input vector do not have the same length!
    

    【讨论】:

    • 这是一个很好的答案,简单,base-R 并且不明显。你让我不必在许多日常用例中加载 assert_that!
    • 这看起来是一个很棒的解决方案,但似乎依赖于 R 版本。它在 3.5.3 上对我不起作用。你用的是什么版本?
    • 没关系,我看到它是作为 R 4.0.0 中的功能添加的。
    【解决方案3】:

    assertiveassertthat 包具有更可读的检查功能。

    library(assertthat)
    assert_that(length(unique(nchar(check))) == 1)
    ## Error: length(unique(nchar(check))) == 1 are not all true.
    
    library(assertive)
    assert_is_scalar(unique(nchar(check)))
    ## Error: unique(nchar(check)) does not have length one.
    
    if(!is_scalar(unique(nchar(check)))) 
    {
      stop("Elements of check have different numbers of characters.")
    }
    ## Error: Elements of check have different numbers of characters.
    

    【讨论】:

    • 不错的包。您是否认为可以直接在断言中实现自定义消息。例如:is_scalar(..., msg="")?
    • @DJJ 我玩弄了这个想法一段时间,但最终决定放弃。 bitbucket.org/richierocks/assertive/issues/16/…如果您对此事有强烈的意见,请在问题上发表评论。
    • 感谢您的信息。您的担忧是有根据的,但有时错误的原因可能很难查明。我通过以下方式找到了解决方法:try(assert_is_scalar(...),stop(mymsg)).
    【解决方案4】:

    或者你可以把它打包。

    assert <- function (expr, error) {
      if (! expr) stop(error, call. = FALSE)
    }
    

    所以你有:

    > check = c("x", "xx", "xxx")
    > assert(length(unique(nchar(check))) == 1, "Elements of your input vector do not have the same length!")
    
    Error: Elements of your input vector do not have the same length!
    

    【讨论】:

    • 这是一个提供默认错误消息的版本,该消息模仿 stopifnot() 的消息。
      assert &lt;- function (expr, msg) { if(missing(msg)) msg &lt;- paste("Condition",deparse(as.list(match.call())$expr), "is not TRUE") if (! expr) stop(msg, call. = FALSE) } 所以,assert(is.character(2)) 返回Error: Condition is.character(dir) is not TRUE
    【解决方案5】:

    stopifnot 嵌入到tryCatch 中,然后使用自定义消息用stop 重铸异常呢?

    类似:

    tryCatch(stopifnot(...,error=stop("Your customized error message"))
    

    与其他一些解决方案不同,这不需要额外的软件包。与使用 if 语句结合 stop 相比,当您使用新的 R 版本时,您保留了 stopifnot 的性能优势。由于 R 版本 3.5.0 stopifnot 按顺序计算表达式并在第一次失败时停止。

    【讨论】:

    【解决方案6】:

    我建议您查看 Hadley 的 testthat 包。它允许进行直观的测试:函数的名称很棒,编写它们的方式就像一个句子——“我希望 length(unique(nchar(check))) 是 [确切|大约] 1”。产生的错误信息丰富。

    请看这里: http://journal.r-project.org/archive/2011-1/RJournal_2011-1_Wickham.pdf

    在你的情况下,

    > library(testthat)
    > check = c("x", "xx", "xxx")
    > expect_that(length(unique(nchar(check))), equals(1))
    Error: length(unique(nchar(check))) not equal to 1
    Mean relative difference: 2
    

    还请注意,您没有@Andrie 提到的问题,有时不得不考虑stopifnot 的双重否定。我知道这看起来很简单,但它让我很头疼!

    【讨论】:

    • 我同意使用testthat 进行测试——我一直都在使用它。但是,我发现testthat 产生的消息非常混乱。这对于开发人员来说是完全可以接受的,但不一定是在包中生成错误消息的前进方向。
    • @Andrie 好点!您的意思是因为在testthat 中您自己没有指定错误消息?
    • +1,感谢您指点我进行测试——它使线程更加全面。可能会接受 Andrie 的回答,因为我正在寻找一种方法来指定用户理解的错误消息。
    • testthat 用于开发时测试; assertiveassertthat 用于运行时测试。看我的回答。
    【解决方案7】:

    已经提供的答案非常好,我的只是该集合的补充。对于某些人来说,使用以下函数形式的单行可能更方便:

    stopifnotinform <- function(..., message = "err") {
      args <- list(...)
      if (length(args) == 0) {
        return(NULL)
      }
      for (i in 1:length(args)) {
        result <- args[[i]]
        if (is.atomic(result) && result == FALSE) {
          stop(message)
        }
      }
    }
    
    # throws an error
    stopifnotinform(is.integer(1L), is.integer(2), message = "Some number(s) provided is not an integer")
    # continues with execution
    stopifnotinform(is.integer(1L), is.integer(2L), message = "Some number(s) provided is not an integer")
    

    请记住,此解决方案只为您提供... 中所有参数的一条(常见)错误消息。

    【讨论】:

    • 太可惜了,这不是默认设置!
    【解决方案8】:

    试试这个:

    same_length <- FALSE
    stopifnot("Elements of your input vector do not have the same length!" = same_length)
    #> Error : Elements of your input vector do not have the same length!
    

    【讨论】:

    • 您的答案可以通过添加有关代码的作用以及它如何帮助 OP 的更多信息来改进。
    猜你喜欢
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    相关资源
    最近更新 更多