资讯专栏INFORMATION COLUMN

[原] 深入对比数据科学工具箱:Python 和 R 的异常处理机制

FreeZinG / 747人阅读

摘要:对于异常机制的合理运用是直接关系到码农饭碗的事情所以,本文将具体介绍一下和的异常处理机制,阐明二者在异常处理机制上的异同。下面将具体介绍二者的异常处理机制。

概述

异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件)。Python和R作为一门编程语言自然也是有各自的异常处理机制的,异常处理机制在代码编写中扮演着非常关键的角色,却又是许多人容易混淆的地方。对于异常机制的合理运用是直接关系到码农饭碗的事情!所以,本文将具体介绍一下Python和R的异常处理机制,阐明二者在异常处理机制上的异同。

异常安全

在了解Python和R的异常机制之前,我们有必要了解一下异常安全的概念。

根据WikiPedia的文献,一段代码是异常安全的,如果这段代码运行时的失败不会产生有害后果,如内存泄露、存储数据混淆、或无效的输出。我们可以知道一段代码的异常安全通常分为下面五类:

异常安全通常分为5个层次:

失败透明:如果出现了异常,将不会对外进一步抛出该异常。(一般比较复杂)

强异常安全:可以运行失败,不过数据会回滚到代码运行前(无副作用)

基本异常安全:运行失败导致的数据变更,使得代码运行前后数据不一致了(有副作用)

最小异常安全:运行失败保存了无效数据,但是还不会引起崩溃,资源不会泄露(进程不会挂)

异常不安全:没有任何保证(进程可能会挂掉)

从上述的5个层次来看,我们可以知道,在平时写代码的时候,对数据库、文件、网络等的IO操作都是需要尽量保证无副作用的,也就是强异常安全。具体来说就是,RDBS操作在失败的时候需要回滚机制、所有IO操作在最后要保证IO连接资源关闭。

其实和多数语言的异常机制的语法是类似的:Python和R都是通过抛出一个异常对象或一个枚举类的值来返回一个异常;异常处理代码的作用域由try开始,以第一个异常处理子句(catch, except等)结束;可连续出现若干个异常处理子句,每个处理特定类型的异常。最后通过finally子句,无论是否出现异常它都将执行,用于释放异常处理所需的一些资源。

下面将具体介绍二者的异常处理机制。

Python 中的异常处理机制

首先,Python 是一门面向对象语言,所有的异常类都是通过继承BaseException类来实现的,我们亦可以通过相应的继承来实现自定义的异常类,比如在工作流调度中使用AirflowException,具体实现可以直接看Airflow的源码。

事实上,这些在我们代码处理范围内的异常其实就是可以分成两个部分:

IO异常:由网络抖动、磁盘文件位置变更、数据库连接变更等引起的IO异常问题。

运行期异常:由于计算或者传输的参数参数类型有误、参数值异常等等发生在运行期的异常,都统一被称为运行期异常。正常来说,IO上的异常我们都要有相应的try-catch-finally机制,在Python也就是如下实现:

try:
   do something with IO
except:
   do something without IO
finally:
   close IO

这里容易犯的一个错误就是在except中又引入了新的IO操作,比如在except中又引入了一个API的POST请求或者数据库写操作等等,这样如果在except阶段又发生了异常,将导致异常信息的丢失。

另一方面,对于可能的运行期异常则需要我们根据具体应用场景的需求来做相应的处理,一般就是遇到一个新的问题加一个新的异常捕获机制,当然这里也就考验到码农程序设计的功利,是否能够未雨绸缪。比如数组长度的检查,传入字典的Key检查等等。Python本身提供了丰富的异常处理类型并且易于拓展,正确使用将可以显著提升程序的鲁棒性(保住码农的饭碗)。

使用try-catch-finally机制是足够简单的,但是在混入returnrasie操作之后,事情就看起来变得有点复杂。

举一个例子:

def test():
    try:
        a = 1/0
    except:
        a = 0
        raise(ValueError,"value error, the division must greater than 0")
        return a
    finally:
        a = 1
        return a
test()

你看这里的返回应该是什么呢?

其实,这里的返回最后应该是 1,而except中raise的异常则会被吃掉。这也是许多人错误使用finanlly的一个很好的例子。

Python在执行带有fianlly的子句时会将except内抛出的对象先缓存起来,优先执行finally中抛出的对象,如果finally中先抛出了return或者raise,那么except段抛出的对象将看起来被吃掉了。

一个段正确的处理方式应该是这样的:

try:
    do IO
    info = {"status":200}
except:
    info = {"status":400}
finally:
    try:
        write log(info)
    except:
        raise(SomeError,"error message")
    close IO

具体的调用栈的过程可以参考这个更加生动的例子:

R 中的异常处理机制

R和Python最大的不同就是 R 本质上是一门强动态类型的非纯函数式编程语言(所谓非纯即存在副作用)而非面向对象语言。从函数式编程语言的角度上讲,R和Erlang、LISP的关系比较近一些。

既然是函数式语言,处理异常也是通过函数式的,而非直接通过面向对象的方式。R 从语法上来看就略显突兀(花括号函数式语言的一大通病):

tryCatch({
  doStuff()
  doMoreStuff()
}, some_exception = function(se) {
  recover(se)
})

如果这段用Python来表达就变成:

try:
  doStuff()
  doMoreStuff()
except SomeException, se:
  recover(se)

事实上正确运用 R 的异常处理机制反而是比较负担小的一种方式:(R 还支持用中文字符集命名变量)

tryCatch({
  结果 <- 表达式
}, warning = function(w) {
    warning()
  ... # 运行期异常
}, error = function(e) {
    stop()
  ... # IO异常
}, finally {
    on.exit()
  ... # 资源回收
}

下面是 Hadley 大神对R的异常处理机制优点的分析:

One of R’s great features is its condition system. It serves a similar purpose to the exception handling systems in Java, Python, and C++ but is more flexible. In fact, its flexibility extends beyond error handling–conditions are more general than exceptions in that a condition can represent any occurrence during a program’s execution that may be of interest to code at different levels on the call stack. For example, in the section “Other Uses for Conditions,” you’ll see that conditions can be used to emit warnings without disrupting execution of the code that emits the warning while allowing code higher on the call stack to control whether the warning message is printed. For the time being, however, I’ll focus on error handling.

The condition system is more flexible than exception systems because instead of providing a two-part division between the code that signals an error and the code that handles it, the condition system splits the responsibilities into three parts–signaling a condition, handling it, and restarting. In this chapter, I’ll describe how you could use conditions in part of a hypothetical application for analyzing log files. You’ll see how you could use the condition system to allow a low-level function to detect a problem while parsing a log file and signal an error, to allow mid-level code to provide several possible ways of recovering from such an error, and to allow code at the highest level of the application to define a policy for choosing which recovery strategy to use.

我的理解是R通过条件机制,然我们可以选择性的在低阶函数中把warning吃掉,这样就不至于影响高阶函数的运行?条件机制将异常分为三阶段而不是两阶段:

1.异常信号捕获
2.异常处理
3.重启机制。

并且我们还可以看到在异常处理中,如何在中阶函数中恢复低阶函数的Error,并且在高阶函数中选择一定的恢复策略。

这段貌似个人理解有误,还请看官指正。

参考资料

RCpp的异常处理

Python对API调用的异常封装例子

什么情况下使用异常处理?

知乎:Python 的异常机制及规范是否相当不人性化?

Python Exceptions Handling

Using R — Basic error Handing with tryCatch()

博客园:R语言里的异常处理与错误控制

Error Handling in R

Beyond Exception Handling: Conditions and Restarts

R 錯誤處理

Stackoverflow: Exception handling in R

CRAN: Exception Handling in R

R 语言摘记(R-LANG, PART II)

Java异常处理

更优阅读体验可直接访问原文地址:https://segmentfault.com/a/11...
作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者 Harry Zhu 的 FinanceR专栏:https://segmentfault.com/blog...,如果涉及源代码请注明GitHub地址:https://github.com/harryprince。微信号: harryzhustudio
商业使用请联系作者。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38098.html

相关文章

  • []深入对比数据科学具箱PythonR Web 编辑器

    摘要:概述工欲善其事必先利其器,如果现在要评选数据科学中最好用的编辑器注意一定是可以通过访问的,和一定是角逐的最大热门,正确使用编辑器可以很大地提升我们的工作效率。 概述 showImg(https://segmentfault.com/img/bVAdol); 工欲善其事必先利其器,如果现在要评选数据科学中最好用的Web 编辑器(注意一定是可以通过Web访问的),RStudio和Jupyt...

    RobinQu 评论0 收藏0
  • []深入对比数据科学具箱PythonR 非结构化数据结构化

    摘要:则在读取数据时将两个中文字段混淆成了一个字段,导致整个数据结构错乱。三条路子全军覆没,这让我情何以堪,好在使用的经验颇丰,通过中文的转换和切割就轻松解决了这个问题。 概述 showImg(https://segmentfault.com/img/bVylLL); 在现实场景中,由于数据来源的异构,数据源的格式往往是难以统一的,这就导致大量具有价值的数据通常是以非结构化的形式聚合在一起的...

    leiyi 评论0 收藏0
  • []深入对比数据科学具箱PythonR之争[2016版]

    摘要:概述在真实的数据科学世界里,我们会有两个极端,一个是业务,一个是工程。偏向业务的数据科学被称为数据分析,也就是型数据科学。所以说,同时学会和这两把刷子才是数据科学的王道。 showImg(https://segmentfault.com/img/bVAgki?w=980&h=596); 概述 在真实的数据科学世界里,我们会有两个极端,一个是业务,一个是工程。偏向业务的数据科学被称为数据...

    whidy 评论0 收藏0
  • [译] 深入对比数据科学具箱Python R C/C++ 实现

    摘要:另外一个我们同时使用两种语言的原因是已有的统计学工具与包。对另一些为读者写数据科学工具的人来说他们从一开始就考虑了这些跨语言。和实际上是用实现的这是条阻力最小的路径。无论是哪个赢得这场语言战争,和都将保持在数据科学届的地位。 showImg(https://segmentfault.com/img/remote/1460000006762469); 概述 几周前,我有幸在 Scipy ...

    jimhs 评论0 收藏0
  • [] 容器定义应用:数据科学容器革命

    摘要:概述随着容器化技术的兴起,数据科学现在最大的一场运动已经不是由一个新的算法或者统计方法发起的了,而是来自的容器化技术。本文将介绍利用容器技术如何加速数据科学在生产环境中的实际应用。 showImg(https://segmentfault.com//img/bVxzYL); 概述 随着容器化技术的兴起,数据科学现在最大的一场运动已经不是由一个新的算法或者统计方法发起的了,而是来自Doc...

    alin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<