之前一直只是在写小程序脚本工具,几乎不会对异常和错误进行控制和处理。

随着脚本结构和逻辑更复杂,脚本输出结果的准确性验证困难,同时已发布脚本的维护也变得困难。所以也开始考虑引入异常处理和测试工具的事情。

不过好像R语言的异常处理似乎有些辣鸡?查了下资料和try的文档说明,感觉说的并不清楚。

在网上查了一些资料,对R语言异常处理做了比较详细的说明,留档作为参考。至于测试工具的问题,后续还是再考虑下。

文章链接:R语言-处理异常值或报错的三个示例

原文参考了以下几个网页:

http://stackoverflow.com/questions/14059657/how-to-skip-an-error-in-a-loop

http://stackoverflow.com/questions/8093914/skip-to-next-value-of-loop-upon-error-in-r-trycatch (这个链接里还连接了非常多的关于R语言异常处理)。

============================= 本人的分割线 ===============================

在开始之前,或许应该参考一下其他语言里面的异常处理机制。

先奉上Java方面的参考资料:深入理解java异常处理机制

除了第4点,其他基本无参考意义。因为R已经将比较底层的东西给隐藏起来,异常(运行时异常、编译异常等)方面的资料也缺少(cran文档库也没有很具体的信息)。所以这里只参考第四点,讨论处理异常机制。

R语言处理异常机制:

异常的处理分为抛出异常捕捉异常

抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。

虽然不确定R中是否存在运行时系统这个概念,但是其他地方的描述,应该是跟Java的异常是一致的。

捕捉异常:

如果tryCatch中调用的语句产生一个错误,它会执行一个以error为参数的函数,并返回这个函数的值。以error为参数的函数,需要将错误本身作为一个参数(这里称之为e),但是我们可以不对它做任何操作。

当然,我们也可以使用较为简单的try语句。选择哪个基于各自的喜好。

假如你的语句产生一个错误,try会返回一个类型为try-error的对象,并将其信息输出至屏幕(若silent=FALSE)。

===== 0524 更 ========

http://stackoverflow.com/questions/8093914/skip-to-next-value-of-loop-upon-error-in-r-trycatch

使用tryCatch需要知道很关键的一点: tryCatch会返回一个对象。见如下代码:

x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error" "condition"

如果在tryCatch中存在一个error,则这个返回的对象会继承error类。我们可以通过inherit函数来检验类继承。

另: 在tryCatch中的参数 error = function(e) e 是什么意思呢?

这有点难到我了。文档中也没有看到很好的解释。这当中的过程是,这个参数会捕获你在tryCatch中的代码表达式产生的任何error信息。假如捕获到error,它则将返回的值作为tryCatch的值(记住tryCatch会返回一个对象)。文档中将其称为calling handler。在 error = function(e)中的e, 就是你代码表达式中的错误信息。

关于在循环代码中使用next:

程序性编程中认为使用next不太好。所以假如想要在for循环中去掉next,可以考虑:

for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
) if(!inherits(possibleError, "error")){
#REAL WORK
useful(i); fun(i); good(i);
} } #end for

======= 果然不只是我对tryCatch的文档云里雾里.... ================

参见:Using R — Basic error Handing with tryCatch()

在开始之前,我们先了解下异常处理中的相关函数列表。以下是这方面函数的最精简的列表了:

  • warning(...) - 生成warnings
  • stop(...) - 生成errors
  • suppressWarnings(expr) - 运行expr表达式, 并忽略任何warnings
  • tryCatch(...) - 运行代码并赋值给异常处理器(exception handlers)

还有其他与异常处理相关的函数,不过以上这些已经足够我们了解R的异常处理了。

R 异常处理与 JAVA中的try-catch-finally机制不同

如果你注意到的话,R在很多问题的处理上和其他大多数语言都不一样。

Java、Python和C以及其他在此维基页面(Exception handling syntax)上提到的语言,都使用语言语句(即关键字)来实现try-catch-finally。但R就特立独行,它使用一个函数来实现....

不过如果你代码写的好的话,tryCatch()函数其实看起来和其他语言的try-catch语法差不多。上代码:

result = tryCatch({
expr
}, warning = function(w) {
warning-handler-code
}, error = function(e) {
error-handler-code
}, finally = {
cleanup-code
}

在tryCatch()中,可以处理两种情况:'warnings' 和 'errors'.要理解每一块代码的意义,关键是要清楚代码的运行状态与作用域。以下节选自?tryCatch文档:

If a condition is signaled while evaluating ‘expr’ then [...] control is transferred to the ‘tryCatch’ call 
that established the handler[...] and the result returned by the handler is returned as the value of the ‘tryCatch’ call. [...]
The ‘finally’ expression is then evaluated in the context in which ‘tryCatch’ was called.

'expr'一次执行一行,直到遇到'condition',然后程序执行会完整地转移给handler。

代码能比文字表达更多信息。文末的独立R脚本展现了一个健壮的异常处理系统的各种特性:

  • 在一个函数中产生warnings和errors
  • 在tryCatch()中设置warning和error处理器(handler)
  • 当函数产生warning或error时,提供备选的返回值
  • 修改warning和error信息的内容
  • 抑制warning信息

复制粘贴文末的脚本,使其可执行,并使用以下命令执行:

$ chmod +x tryCatch.Rscript
$ ./tryCatch.r 1
$ ./tryCatch.r 0
$ ./tryCatch.r a
$ ./tryCatch.r
$ ./tryCatch.r warning
$ ./tryCatch.r error
$ ./tryCatch.r suppress-warnings

注意当'suppress-warnings'时发生了什么。

以下是一些你需要知道的,关于这个实验脚本的信息:

  1. tryCatch()的使用并不难(一旦你知道如何使用)
  2. condition handler 能访问到warning()和stop()信息
  3. 在传递函数参数之前,准备好合适的类型转换。
  4. 最理想的情况是,tryCatch()的代码表达式只是一个单独的函数。

以下是tryCatch.Rscript范例脚本。Hope You enjoy Error handling.

#!/usr/bin/env Rscript
# tryCatch.Rscript -- experiments with tryCatch # Get any arguments
arguments <- commandArgs(trailingOnly=TRUE)
a <- arguments[1] # Define a division function that can issue warnings and errors
myDivide <- function(d, a) {
if (a == 'warning') {
return_value <- 'myDivide warning result'
warning("myDivide warning message")
} else if (a == 'error') {
return_value <- 'myDivide error result'
stop("myDivide error message")
} else {
return_value = d / as.numeric(a)
}
return(return_value)
} # Evalute the desired series of expressions inside of tryCatch
result <- tryCatch({ b <- 2
c <- b^2
d <- c+2
if (a == 'suppress-warnings') {
e <- suppressWarnings(myDivide(d,a))
} else {
e <- myDivide(d,a) # 6/a
}
f <- e + 100 }, warning = function(war) { # warning handler picks up where error was generated
print(paste("MY_WARNING: ",war))
b <- "changing 'b' inside the warning handler has no effect"
e <- myDivide(d,0.1) # =60
f <- e + 100
return(f) }, error = function(err) { # error handler picks up where error was generated
print(paste("MY_ERROR: ",err))
b <- "changing 'b' inside the error handler has no effect"
e <- myDivide(d,0.01) # =600
f <- e + 100
return(f) }, finally = { print(paste("a =",a))
print(paste("b =",b))
print(paste("c =",c))
print(paste("d =",d))
# NOTE: Finally is evaluated in the context of of the inital
# NOTE: tryCatch block and 'e' will not exist if a warning
# NOTE: or error occurred.
#print(paste("e =",e)) }) # END tryCatch print(paste("result =",result))

  

[R]R语言里的异常处理与错误控制的更多相关文章

  1. 【C++】异常简述(一):C语言中的异常处理机制

    人的一生会遇到很多大起大落,尤其是程序员. 程序员写好的程序,论其消亡形式无非三种:无疾而终.自杀.他杀. 当然作为一名程序员,最乐意看到自己写的程序能够无疾而终,因此尽快的学习异常处理机制是非常重要 ...

  2. (转)\r \r\n \t 的区别

    小风吹雪 \r \r\n \t 的区别 http://www.360doc.com/content/12/0530/15/16538_214756101.shtml \n 软回车:       在Wi ...

  3. C语言中的异常处理

    一 前言: 异常处理,对于做面向对象开发的开发者来说是再熟悉不过了,例如在C#中有 try { ... } catch( Exception e){...} finally{ ..... } 在C++ ...

  4. 文件操作:w,w+,r,r+,a,wb,rb

    1.文件操作是什么? 操作文件: f = open("文件路径",mode="模式",encoding="编码") open() # 调用操 ...

  5. 把十进制整数转换为r(r=2)进制输出(顺序栈实现)

    上周的第二个作业补上~~ 上周的要求: 1.给出顺序栈的存储结构定义. 2.完成顺序栈的基本操作函数. 1)      初始化顺序栈 2)      实现入栈和出栈操作 3)      实现取栈顶元素 ...

  6. c语言里用结构体和指针函数实现面向对象思想

    一.基础研究 观察如下两个程序a.c和b.c: A.c: B.c: 这两个程序都是要实现在屏幕上第10行40列打印一个绿色的字符c: 这两个程序的数据组织方式是一样的,都是使用结构体,而且对共性和个性 ...

  7. [原创]C语言里为何会有“2+2=5”的结果

    原文链接:C语言里为何会有“2+2=5”的结果 写这篇原创文章是因为看到了极客中的一篇文章<有趣各种编程语言实现2+2=5>,其中C语言是这样实现的: int main() { ″; // ...

  8. const分别在C和C++语言里的含义和实现机制

    const的含义        简单地说:const在c语言中表示只读的变量,而在c++语言中表示常量. C语言 const是constant的缩写,是恒定不变的意思,也翻译为常量,但是很多人都认为被 ...

  9. python文件操作各种模式和常用方法总结r r+ rb r+b

    1.读,r r+ rb r+b read() 全部读取 read(n) 读取一部分 r模式下:n 个字符. rb模式下:n个 字节. readline() 按行读取. readlines() 返回个列 ...

随机推荐

  1. iOS - 定制多样式二维码

    二维码/条形码是按照某种特定的几何图形按一定规律在平台(一维/二维方向上)分布的黑白相间的图形纪录符号信息.使用若干个与二进制对应的几何形体来表示文字数值信息.   最常见的二维码功能包括信息获取.网 ...

  2. NYOJ题目768移位密码

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAtIAAAJqCAIAAACJkTDlAAAgAElEQVR4nO3du3Ljvpa34b4J574Qx7

  3. 学习hibernate @Entity该导入哪个包

    1.在@Entity时很容易顺手导入@org.hibernate.annotations.Entity这个包,结果导致了异常.其实应该导入的是@javax.persistence.Entity Alw ...

  4. Python 文件处理

    文件夹: 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir() 函数用来删除一个文件:os.remove() 删 ...

  5. html练习

    border-left:100px solid transparent;    左边框隐藏 transform:rotate(45deg);   div旋转45度 用css做一个三角形 <sty ...

  6. Android源码-学习随笔

    在线代码网站1:http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/ 书籍: ...

  7. gnuplot安装问题(set terminal "unknown")

    今天在系统同上要装个gnuplot,原来用的都是拷好的虚拟机.这也是第一次装.本来以为分分钟的事,却不料遇到不少麻烦.记录一下,供大家参考 一,快速开始安装 ubuntu下那自然是: sudo apt ...

  8. 上四条只是我目前总结菜鸟们在学习FPGA时所最容易跑偏的地

    长期以来很多新入群的菜鸟们总 是在重复的问一些非常简单但是又让新手困惑不解的问题.作为管理员经常要给这些菜鸟们普及基础知识,但是非常不幸的是很多菜鸟怀着一种浮躁的心态来学习 FPGA,总是急于求成. ...

  9. Unity3d 提示 "The scripts file name does not match the name of the class defined in the script!"的解决办法

    有两个原因,一个是文件的名称和类名不一致 第二个原因是有命名空间, 排除应该是可以修复的

  10. c文件操作 (转)

    文件文件的基本概念 所谓“文件”是指一组相关数据的有序集合. 这个数据集有一个名称,叫做文件名. 实际上在前面的各章中我们已经多次使用了文件,例如源程序文件.目标文件.可执行文件.库文件 (头文件)等 ...