[虾说算法] 若为性能计,非必要,少用异常捕捉

什么是异常捕捉

异常捕捉是指在程序运行过程中,遇到异常情况时,通过捕获异常并处理异常,使程序能够继续运行,而不是崩溃。这是现代编程语言里面的一个重要的概念。

例如在Python里面,我们可以使用try…except语句来捕捉异常。

def division(a,b):
    try:
        # 可能会抛出异常的代码
        return a/b
    except ZeroDivisionError:
        # 处理异常的代码
        print("除数不能为0")
        return None

像上面这个函数,我们可以捕捉除数为0的异常。如果没有这个函数,那么这个功能放到整个流程里面,就有可能出现程序中断,如下所示:

在这里插入图片描述

可以看见,如果不用异常捕捉程序在运行到运算的时候,出现了异常,导致程序崩溃,后面的流程就执行不下去了。

而用了异常捕捉,程序在运行到运算的时候,出现了异常,但是我们捕捉到了异常,所以程序没有崩溃,后面的流程继续执行。

这里我们用了一个ZeroDivisionError异常,来捕捉除数为0的异常。以此类推,还可以加上其他的异常,例如类型异常TypeError:

def division(a,b):
    try:
        # 可能会抛出异常的代码
        return a/b
    except ZeroDivisionError:
        # 处理异常的代码
        print("除数不能为0")
        return None
    except TypeError:
        # 处理异常的代码
        print("类型错误")
        return None
    except:
        # 处理异常的代码
        print("其他异常")
        return None

当然,我们不可能列举所有的异常,所以我们可以使用一个通用的异常捕捉,来捕捉所有的异常。

异常捕捉的应用与性能案例

所以,有些写算法的同学,为了方便,会脑洞大开的利用异常来进行逻辑判定,例如判定你输入的是不是数字,就会这样写算法:

def isNumeric(val):
    try:
        val + 1
        return True
    except TypeError:
        return False

在这里插入图片描述

(别笑……这是ArcGIS的官方源码……)

实际上算法是可以成功运行的(效果还不错),如下所示:

在这里插入图片描述

而Python官方对于数值的判定,建议使用的isinstance()或者说type()函数,如下所示:

def isNumeric2(val):
    return isinstance(val, (int, float, complex))

def isNumeric3(val):
    return type(val) == int or type(val) == float or type(val) == complex

运行结果如下:

在这里插入图片描述

在功能一样的情况下,我们来测试一下这几个函数的运行效率,首先是结果True的情况:

在这里插入图片描述

我们发现,如果结果是True,用数学运算的效率是最高的,因为不他走异常捕捉,而且也不走逻辑判断,加法运算是可以直接走CPU的。

其次是type,最后是isinstance的性能。

然后我们来进行false测试:

在这里插入图片描述

在这里插入图片描述

我们可以看见,不管是type还是isinstance,在结果是False的情况下,性能要远远高于走try...except的异常捕捉。

这里,从异常捕捉的原理来看,异常发生并进入 except 处理时,会产生明显性能开销,其原因包括:

  • 生成异常对象(如 ValueError 实例),需保存异常追踪信息(调用栈、错误位置等);
  • 遍历 except 块列表匹配异常类型;
  • 中断正常执行流程,切换到异常处理上下文。

结论:

  • 在对问题可以预见的情况下,不建议用 try-except 替代常规条件判断:如判断字符串是否可转整数,应优先用 str.isdigit() 而非依赖 try int(s) except ValueError(后者在高频调用场景会导致性能瓶颈)。

所以,对于第一个除法代码函数的应用,如果要追求最好性能的话,我们可以在一些可以预期错误的问题上,用isinstance()或者type()函数来替代异常捕捉。

代码如下:


def division(a,b):
    try:
        if not isinstance(a, (int, float, complex)) or not isinstance(b, (int, float, complex)):
            print("非数值无法进行除法运算")
            return None
        elif b == 0:
            print("除数不能为0")
            return None
        # 可能会抛出异常的代码
        return a/b
    except Exception as ex:
        # 处理异常的代码
        print("其他异常", ex)
        return None

在数学运算上,绝大部分异常就是这两列,但是你也不敢保证所有的异常都在这两列,所以最后还是要追加一个except,反正一些特殊的意外。

  • 对于很多无法预计的问题,适合处理 “意外异常”:如网络请求超时、文件突然被删除等低概率异常,此时性能消耗可接受,且代码更简洁。

在这里插入图片描述

打完收工。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虾神说D

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值