首页 > 技术文章 > Python 中的异常处理

dy99 2021-06-10 18:29 原文

1 异常处理

异常即是一个事件,该事件会在程序执行过程中发生,会让程序崩溃,中止执行;为了防止程序中断,增加程序的健壮性,可以做一些预处理,当Python脚本发生异常时可以捕获处理它。

1.1 常见异常

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
 
  Python的异常处理能力是很强大的,它有很多内置异常,可向用户准确反馈出错信息,在Python中,异常也是对象,可对它进行操作。BaseException是所有内置异常的基类,但用户定义的类并不直接继承BaseException,所有的异常类都是从Exception继承,且都在exceptions模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。一旦引发并且没有捕捉SystemExit异常,程序执行就会终止。

1.2 异常处理语法结构

try:
<语句>        #运行别的代码
except <异常名称><语句>        #如果在try部份引发了'name'异常
except (<异常A>,<异常B>):
<语句>        #如果引发了'name'异常,获得附加的数据
else:
<语句>        #如果没有引发异常,则执行else中的语句
finally:   
<语句>    # 无论是否发生异常都将执行finally代码
raise

1.3 异常捕获场景

如果我们已经知道这种类型的错误,那么就可以通过一个异常来捕捉这个错误。我们可以通过try...except 来预知处理这个异常。
1.3.1 指定单个异常
只能用来处理指定的异常情况,如果未捕获到异常,则报错。
try:
    open("test.text")
except FileNotFoundError as e:  # as+变量名:重命名异常信息
    print("文件操作失败,原因:", e)
# 执行结果:
文件操作失败,原因: [Errno 2] No such file or directory: 'test.text'
1.3.2 捕获多个异常
一般建议捕获可能出现的多个异常(按照先子类后父类的顺序),并且针对性的写出多个异常处理代码。异常可以分别处理,或者放在一行处理。
方法一:多分支
def dev(a, b):
    try:
        c = float(a)/float(b)
    except ValueError as e:  # as+变量名:重命名异常信息
        print("字符串不能做除法,具体异常如下:", e)
    except ZeroDivisionError as e:
        print("0不能作为除数,具体异常信息:", e)
dev(2, 0)
 
异常处理规则:
①第一个except中定义的异常与引发的异常匹配,则执行该except中的语句;
②引发的异常不匹配第一个except,则会搜索第二个except,允许编写的except数量没有限制
③所有的except都不匹配,则异常未捕获就会抛出
方法二:一行except同时处理多个异常
def dev(a, b):
    try:
        c = float(a)/float(b)
    except (ValueError, ZeroDivisionError) as e:  # as+变量名:重命名异常信息
        print("具体异常如下:", e)
dev(2, 0)
1.3.3 万能异常
在python的异常中,有一个万能异常:Exception,它可以捕获任意异常。它是一把双刃剑,有利有弊,我们要视情况使用,优点是什么异常都会被捕获,但是会导致我们不清楚是哪种类型的异常信息,因此可与多分支结合使用,需要注意的是,万能异常一定要放在最后,否则就没有意义了。
def dev(a, b):
    try:
        c = float(a)/float(b)
    except Exception as e:  # as+变量名:重命名异常信息
        print("具体异常如下:", e)
dev(2, 0)
1.3.4 异常中的else
如果判断完没有某些异常之后还想做其他事,就可以使用下面这样的else语句,else下的语句是只有无异常时才会执行,否则不执行。else和finally是可选的,可能会有0个或多个except,但是,如果出现一个else的话,必须有至少一个except。
def dev(a, b):
    try:
        c = float(a)/float(b)
    except Exception as e:  # as+变量名:重命名异常信息
        print("具体异常如下:", e)
    else:
        print("无异常")
dev(2, 0)
1.3.5 异常中的finally
try...finally...语句无论是否发生异常都将会执行最后的代码。
try:
     <语句>
finally:
    关闭浏览器
    driver.quit()

1.4 异常的其他用途

捕获异常不仅是为了防止程序中断,还可以通过异常进行场景处理,如以下代码,通过捕获异常IndexError取代列表长度判断,减少代码量。
# 题目:给你一个非空数组,返回此数组中第三大的数 。如果不存在,则返回数组中最大的数。
def ThirdNum(num_list):
    if num_list:
        try:
            return sorted(list(set(num_list), reverse=False)[2]
        except IndexError:
            return sorted(num_list, reverse=True)[0]
    else:
        print("传入数组不能为空")
if __name__ == '__main__':
    alist = [2, 9]
    print(ThirdNum(alist))

 

推荐阅读