第十三篇:python之异常处理
什么是异常
异常就是程序运行时发生错误的信号,Python遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,则程序就会用所谓的回溯(Traceback,一种错误信息)来终止执行。
为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,我们需要对异常进行处理。
下面编写一个同样功能的代码,对比做异常处理和不做异常处理的区别。
'''不做异常处理''' num = int(input('请输入数字>>>')) #当输入的非数字时,则会触发异常,终止程序执行,下面的代码不会被执行,导致程序崩溃。 print('你输入的整数是:{}'.format(num))
如果发生的错误是可预知的,我们可以用if语句进行处理:在错误发生之前进行预防。
'''做异常处理''' num = input('请输入数字>>>') #当输入的非数字时,则会触发异常,终止程序执行,下面的代码不会被执行,导致程序崩溃。 if num.isdigit(): print('你输入的整数是:{}'.format(int(num))) else: print('你输入的不完全是数字。')
python的异常处理机制
在所有的程序中,都会遇到异常,有些异常是代码编写的时候产生的,在前期过程中可能会直接导致程序无法运行。这一类的异常,在编写代码的时候,程序可以直接排查修改。但有些异常,是在程序运行过程中产生的,可能是与用户交互获取的数据无法识别,也或者是网络请求失败导致程序无法继续等等不可预知的异常。为了防止程序崩溃,这一类的错误,就需要程序员在编写的时候提前考虑到并进行相应的异常处理。每一门语言基本都有自己相应的异常防御机制,python尤其如此,不仅给了错误调试语句,还提供了庞大的内置异常类,让我们可以精准的针对不同异常给出不同的处理方式。
异常分类
异常名称 | 描述 |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
WindowsError | 系统调用失败 |
RuntimeError | 一般的运行时错误 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
OSError | 操作系统错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
OverflowError | 数值运算超出最大限制 |
SyntaxWarning | 可疑的语法的警告 |
ZeroDivisionError | 当除运算或模零在所有数值类型运算时引发 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 当生成的错误不属于任何类别时引发 |
UnicodeEncodeError | Unicode 编码时错误 |
UserWarning | 用户代码生成的警告 |
UnicodeTranslateError | Unicode 转换时错误 |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用试图访问已经垃圾回收了的对象 |
KeyError | 映射中没有这个键 |
异常捕获
异常:是指在程序执行过程中发生的一个事件,会影响程序的正常运行,当程序运行时系统接受到异常对象时,会寻找能处理这异常的代码并把当前异常对象交给其处理。所以一般需要进行捕获异常并处理。异常的捕获使用try/except/finally语句进行捕获操作。
处理异常的语法结构:
'''异常处理''' try: '''被检测的代码块''' num = input('请输入数字>>>') print('你输入的整数是:{}'.format(int(num))) except: #若不写异常类型,则默认捕获所有异常。 print('你输入的不完全是数字') #可多分支捕获不同异常类型,进行相应的异常处理。 try: '''被检测的代码块''' num = input('请输入数字>>>') print('你输入的整数是:{}'.format(int(num))) except TypeError: '''如果捕获到TypeError,就执行这个位置的逻辑''' print('捕获到TypeError时的处理逻辑') except ValueError as e: print(e) else: print('被检测代码正常运行,就执行这个位置的逻辑') finally: print('不管被检测代码是否有异常,该逻辑代码块都要执行,通常是进行清理工作') #可通过所以异常的基类BaseException,捕获所有异常,通过常规错误的基类Exception,捕获常规错误。 try: num = input('请输入数字>>>') print('你输入的整数是:{}'.format(int(num))) except BaseException: print('你输入的不完全是数字')
断言
除了不可控的异常出现之外,有些代码需要特定的运行条件,那么,我们可以认为抛出异常。python中抛异常的方式有两种,断言,或者raise语句。其中,断言需要判定条件,而raise是直接后接需要抛出的异常类型。二者应用场合在我的理解中略有分别,断言常常使用于根据条件成立来决定抛异常的与否,通常用于为接下来执行的代码正常运行从而进行数据校验。例如,一个变量初始值为空,在程序运行到一半它从网络获取数据,如果没有数据,那么,程序无法执行。就可以使用断言来判定变量是否为空,如果为空,则直接抛异常,并给出告警。当然,raise可以实现同样功能,不过它需要一个if判别。因此,在代码使用上来讲,断言更为简洁,并且它也能被exception捕获。我们首先来看下断言机制。
try: num = eval(input('请输入一个结果等于9的表达式:')) except BaseException: print('你输入的表达式不规范') else: """断言关键字使用,后接判定条件,如果条件成立,则无异常。不成立,抛AssertionError异常。<br>用","分割,后接给出的告警信息。告警信息也可以省略""" assert num == 9, "脑子是个好东西,我希望你有一个。好好计算!" print("你真聪明!")
抛出异常
程序的执行过程中如出现异常事件,可以生成一个异常对象,断言的语句用于已知的条件调试相对简洁。但有些异常时python定义的异常类里面存在的,为了方便快捷,我们可以直接抛出,无需定义异常信息,这时就需要raise来解决了。
raise NameError("name error!")#抛出一个NameError异常,可以给一个打印信息,也可以不给 #常规自定义具体异常信息应该尽量抛Exception类 这里仅做其他类示范。 print("然而并没有错误!") #抛出异常后尝试打印点神马
如上,raise可以直接抛出python自带的异常类,一看就知道哪里出了错误,所以如果不需要条件判定的是自定义异常信息,尽量抛Exception类。这样不至于混淆异常信息。以上代码都立足于功能示范,在实际使用中,一旦抛出异常,程序就会崩溃。所以常规的抛异常大多用于代码调试。如果是为了预防未知信息,抛异常应该出现try--except语句的try下属代码模块,然后用except捕获,再给出相应的解决方案。
自定义异常类
python允许你根据需求定义自己的异常类,但必须继承所异常类的基类BaseException。
class EgonException(BaseException): def __init__(self,msg): self.msg=msg def __str__(self): return self.msg try: raise EgonException('类型错误') except EgonException as e: print(e)