好多时候,都忘记自己还是个技术博主了

可以直接看结论

有福利

什么是异常捕捉

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

例如在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, (intfloatcomplex))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, (intfloatcomplex)) or not isinstance(b, (intfloatcomplex)):            print("非数值无法进行除法运算")            return None        elif b == 0:            print("除数不能为0")            return None        # 可能会抛出异常的代码        return a/b    except Exception as ex:        # 处理异常的代码        print("其他异常", ex)        return None

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

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


打完收工。

我是福利