2017-08-02 20:42:11
stop()
函数退出执行warning()
函数显示潜在问题suppressWarnings()
函数屏蔽警告message()
将运行中的重要信息提示给用户suppressMessage()
函数屏蔽提醒信息错误
mean(a)
Error in mean(a) : object 'a' not found
警告
log(-1)
Warning in log(-1) : NaNs produced [1] NaN
提醒
library(epiR)
Package epiR 0.9-87 is loaded Type help(epi.about) for summary information
Fred Brooks: Much of the essence of building a program is in fact the debugging of the specification.
f1
逐级调用低级函数,构成一个调用堆栈(call stack)traceback()
在堆栈中回溯f1 <- function(x1) f2(x1) f2 <- function(x2) f3(x2) f3 <- function(x3) f4(x3) f4 <- function(x4) f5(x4) f5 <- function(x5) "A" + x5 f1(1)
Error in "A" + x5 : non-numeric argument to binary operator
点"Show Traceback",或traceback()
traceback()
5: f5(x4) at #1 4: f4(x3) at #1 3: f3(x2) at #1 2: f2(x1) at #1 1: f1(1)
debug()
函数 (事后要undebug()
)包括5个按钮:
n
/F10): 执行函数的下一步s
/Shift+F4): 类似Next,但如下一步是个函数,则进入该函数逐行调试f
/Shift+F6): 完成执行当前循环块或函数c
/Shift+F5): 结束调试并完成执行剩余的代码结束(Stop, Q
/Shift+F8): 退出调试和执行,返回全局环境
Error in "A" + x5 : non-numeric argument to binary operator Called from: f5(x4) Browse[1]> n
getOption("error")
## NULL
browser
,则遇错自动进入动态调试options(error = browser)
browseOnce <- function() { old <- getOption("error") function() { options(error = old) browser() } } options(error = browseOnce())
Error in "A" + x5 : non-numeric argument to binary operator Called from: f5(x4) Browse[1]> recover() Enter a frame number, or 0 to exit 1: f1(1) 2: #1: f2(x1) 3: #1: f3(x2) 4: #1: f4(x3) 5: #1: f5(x4) 6: #1: (function () { .rs.breakOnError(TRUE) })() 7: .rs.breakOnError(TRUE) 8: eval(substitute(browser(skipCalls = pos), list(pos = (length(sys.frames()) - frame) + 2)), envir = sys.frame(frame)) ...
dump_and_quit <- function() { # 调试信息写入last.dump.rda dump.frames(to.file = TRUE) # 以出错状态退出R q(status = 1) } options(error = dump_and_quit)
load("last.dump.rda") debugger()
browser
browser()
插入到第一行,即相当于运行时debug()
debug()
函数正是这么做的f <- function(x){ if (1 %in% x){ browser() return("There is 1") }else{ return("There is no 1") } } f(1:4)
Called from: f(1:4) Browse[1]> x [1] 1 2 3 4 Browse[1]> n debug at #4: return("There is 1") Browse[2]> n [1] "There is 1"
options(warn=2)
message2error <- function(code) { withCallingHandlers(code, message = function(e) stop(e)) }
f <- function() message("yup") message2error(f())
Error in message("yup") : yup
出现错误默认整体退出,不返回结果
f <- function(x){ log(x) 2 } f("1")
Error in log(x) : non-numeric argument to mathematical function
try捕捉到的错误结果属于"try-error"类
class(try(log("1")))
[1] "try-error"
try()
可捕捉错误信息,并继续执行代码
f <- function(x, ...){ try(log(x), ...) 2 } f("1")
Error in log(x) : non-numeric argument to mathematical function [1] 2
try(..., silent=TRUE)
隐藏错误信息
f("1", silent=TRUE)
[1] 2
tryCatch(expr, ..., finally)
tryCatch
不但能捕捉错误,还提供了一个异常处置框架举个例子:
show_cond <- function(expr, ...){ tryCatch(expr, error=function(cond) "error", warning=function(cond) "warn", message=function(cond) "msg", finally=cat("The output: ")) }
show_cond(log(10))
The output: [1] 2.302585
show_cond(message("!"))
The output: [1] "msg"
show_cond(log(-1))
The output: [1] "warn"
show_cond(log("1"))
The output: [1] "error"
f1 <- function() f2() f2 <- function() stop("Stop!") tryCatch(f2(), error=function(e) print(sys.calls()))
[[1]] tryCatch(f2(), error = function(e) print(sys.calls())) [[2]] tryCatchList(expr, classes, parentenv, handlers) [[3]] tryCatchOne(expr, names, parentenv, handlers[[1L]]) [[4]] value[[3L]](cond)
withCallingHandlers(f2(), error=function(e) print(sys.calls()))
[[1]] withCallingHandlers(f2(), error = function(e) print(sys.calls())) [[2]] f2() [[3]] stop("Stop!") [[4]] .handleSimpleError(function (e) print(sys.calls()), "Stop!", quote(f2())) [[5]] h(simpleError(msg, call)) Error in f2() : Stop!
condition <- function(subclass, message, call = sys.call(-1), ...) { structure( class = c(subclass, "condition"), list(message = message, call = call), ... ) }
err.neg <- condition( c("neg_error", "error"), "Cannot be negative!") wrn.zero <- condition( c("zero_warn", "warning"), "Cannot be zero!") msg.greet <- condition( c("greet_msg", "message"), "Bingo!")
newLog <- function(x){ if (x<0) stop(err.neg) else if (x==0) warning(wrn.zero) else message(msg.greet) return(log(x)) }
tryCatch(newLog(1))
Bingo![1] 0
tryCatch(newLog(-1))
Error: Cannot be negative!
tryCatch(newLog(bb))
Error in newLog(bb) : object 'bb' not found
墨菲定律(Murphy's Law): 凡是可能出错的事,准会出错。
match.arg
+ if/stop
或 stopifnot
f <- function(x, fun=c("mean", "median")){ # 确保x是纯数值 stopifnot(all(sapply(x, is.numeric))) # 确保fun只能是列表中规定的三个 fun <- match.arg(fun) switch(fun, mean=lapply(x, mean), median=lapply(x, median), var=lapply(x, var)) }
f(1:10, "sum")
Error in match.arg(fun) : 'arg' should be one of “mean”, “median”, “var”
f <- function(x, fun=c("mean", "median")){ library(assertthat) assert_that(all(sapply(x, is.numeric))) fun <- match.arg(fun) switch(fun, mean=lapply(x, mean), median=lapply(x, median), var=lapply(x, var)) }
f(list(1:10, 11:20, "a"), "mean")
Error: Elements 3 of sapply(x, is.numeric) are not true
subset
、transform
、with
substitute
、quote
、parse
、eval
等函数自定义非标准求值函数f1 <- function(df, cond) df[cond,]
f1(mtcars, mtcars$mpg>33)
mpg cyl disp hp drat ... carb Toyota Corolla 33.9 4 71.1 65 4.22 ... 1
f2 <- function(df, cond) subset(df, cond)
f2(mtcars, mpg>33)
Error in eval(e, x, parent.frame()) : object 'mpg' not found
意外降维: [
getCol <- function(df, i) df[,i] getCol(mtcars[,1], 1)
Error in df[, i] : incorrect number of dimensions
sapply(mtcars[1:8, 1], mean)
[1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4
结构变异: sapply
sapply(integer(), identity)
list()
避免降维: drop=FALSE
,simplify=FALSE
getCol <- function(df, i) df[, i, drop=FALSE] getCol(mtcars[, 1, drop=FALSE], 1)
sapply(mtcars[1:8, 1, drop=FALSE], mean)
保障数据结构: 用vapply
代替sapply
vapply(integer(), identity, 0L)
integer(0)
vapply(list(c(1, 2), c(1, 3, 1)), function(v) which(v==1), 0)
Error in vapply(list(c(1, 2), c(1, 3, 1)), function(v) which(v == 1), : values must be length 1, but FUN(X[[2]]) result is length 2
rlog <- function(x) lapply(x,log); rlog(list(1:4,"a"))
Error in FUN(X[[i]], ...) : non-numeric argument to mathematical function
rlog <- function(x) lapply(x, function(v) tryCatch(log(v), error=function(cdt) NULL)) rlog(list(1:4, "a"))
[[1]] [1] 0.0000000 0.6931472 1.0986123 1.3862944 [[2]] [1] NULL
Thank you!