可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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).
回答1:
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
回答2:
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).
回答3:
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
回答4:
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:
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