warnings() does not work within a function? How ca

2019-04-06 19:13发布

op <- options(warn=0)  #although doesn't work for any value of warn
assign("last.warning", NULL, envir = baseenv())  
thisDoesntWork<- function() {
warning("HEY, this is definitely a warning!")
cat(paste("number of warnings:",length(warnings())))
}   
>thisDoesntWork()
Warning in thisDoesntWork() : HEY, this is definitely a warning!
number of warnings: 0

Number of warnings should be 1 rather than 0 - it seems that warnings() returns nothing if called within a function. Why? How can one work around this to check within a function if warnings occurred, and print them out?

I don't want to use tryCatch, because then I lose the value that the function returns (it may still return a valid value, even if it generated a warning).

5条回答
看我几分像从前
2楼-- · 2019-04-06 19:58

probably this is a very very bad workaround...

fw<-function(){warning("warn...");return(99)}
fn<-function(){return(88)}

f<-function(){
    w<-0
    v<-NULL
    v<-tryCatch(fw(),warning=function(w){w})
    if("warning"%in%class(v)){
        w<-w+1 # e.g., count up the number of warning
        v<-fw()
    }
    print(v)

    v<-NULL
    v<-tryCatch(fn(),warning=function(w){w})
    if("warning"%in%class(v)){
        w<-w+1 # e.g., count up the number of warning
        v<-fn()
    }
    print(v)
}
f()

calling the function twice if warning occurs... though I believe that there must be more elegant solutions

查看更多
冷血范
3楼-- · 2019-04-06 20:02

The warnings are issued not before the function returns. See the documentation for options("warn"):

options(warn=1L)
thisDoesntWork()
#Warning in thisDoesntWork() : HEY, this is definitely a warning!
#number of warnings: 1 
查看更多
何必那么认真
4楼-- · 2019-04-06 20:05

Here is a workaround

..my_warning <- 0L

thisDoesWork<- function(){
    assign("last.warning", NULL, envir = baseenv())  
    warning("HEY, this is definitely a warning!", {..my_warning <<- ..my_warning+1L;""})
    str(last.warning)
    cat(paste("number of warnings:", ..my_warning, "\n"))
}


thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 1 
>     thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 2 
>     thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 3 
> 
查看更多
做自己的国王
5楼-- · 2019-04-06 20:09

Your example does return a warning.

> assign("last.warning", NULL, envir = baseenv())  
> thisDoesntWork <- function() {
+   warning("HEY, this is definitely a warning!")
+   cat(paste("number of warnings:",length(warnings())),"\n")
+ }
> thisDoesntWork()
number of warnings: 0 
Warning message:
In thisDoesntWork() : HEY, this is definitely a warning!
> warnings()  # HEY, here's your warning!!!
Warning message:
In thisDoesntWork() : HEY, this is definitely a warning!

The documentation isn't explicit, but I don't think last.warning gets set until the call finishes (especially given the call is part of what can be returned).

查看更多
smile是对你的礼貌
6楼-- · 2019-04-06 20:10

Here's the code for suppressWarnings

function (expr) 
{
    withCallingHandlers(expr, warning = function(w) invokeRestart("muffleWarning"))
}

I've tweaked it a little to count the number of warnings instead.

countWarnings <- function(expr) 
{
    .number_of_warnings <- 0L
    frame_number <- sys.nframe()
    ans <- withCallingHandlers(expr, warning = function(w) 
    {
      assign(".number_of_warnings", .number_of_warnings + 1L, 
        envir = sys.frame(frame_number))
      invokeRestart("muffleWarning")
    })
    message(paste("No. of warnings thrown:", .number_of_warnings))
    ans
}

A test:

countWarnings(log(-1))
No. of warnings thrown: 1
[1] NaN

Another test:

foo <- function()
{
  warning("first warning!")
  warning("second warning!")
  warning("third warning!")
  invisible()
}
countWarnings(foo())
No. of warnings thrown: 3
NULL
查看更多
登录 后发表回答