Python课程回顾(day25)
异常
1.什么是异常?
我们在Pycharm中运行程序的时候,最怕的应该就是一行行的红色的字体,之前我们将这种情况称之为报错,那么其实我们更应该明白,这就是所谓的异常
异常:异常就是一种错误发生的信号,在我们运行程序的过程中,一旦发生错误且没有相应的处理方法,那么这个错误就会抛出一个异常,从而终止掉所有程序的运行
2.异常的组成
整体的来说,一个异常又分为三部分
异常的追踪信息:即在出现异常时,Pycharm会自动将出现异常的当前行以及导致当前行出现异常的所有关联行返回给我们
异常的类型:异常的类型则表示我们的异常是哪种类型的异常.
例如一下常见的异常
KeyError Key异常 d = {'a': 1, 'b': 2} print(d['c']) 字典内不存在的Key TypeError 类型异常 x = 'a'+1 字符串不能与数字相加 ValueError 值异常 int('a') 由字母组成的字符串不能被int ZeroDivisionError 运算异常 x = 1/0 任何数字都不能除以0 IOError 与文件的异常 f = open('README', 'r', encoding='utf-8') f.close() f.read() 读取一个已经关闭的文件 FileNotFoundError 查找文件异常 f = open('XXXX', 'r', encoding='utf-8') 文件XXXX不存在 f.read() SyntaxError 语法异常 x = 1 if if后没有任何条件 print(x) NameError 名称异常 x = 1 print(y) y不存在 AttributeError 属性异常 class X: pass print(X.aaa) X没有aaa这个属性
异常的具体信息:根据异常类型,我们还可以得到一些我们出现异常的具体描述来帮助我们修改代码
如下:
class X: pass print(X.aaa)
输出结果: (异常类型: 对象X没有aaa对象) AttributeError: type object 'X' has no attribute 'aaa'
3.异常的分类
总的来说异常又分为两大种类:
语法异常:会在定义阶段就开始识别,若出现语法异常则会在运行程序时的瞬间直接抛出异常,一定要避免语法错误
逻辑异常:即在程序运行过程中出现的异常,经过一系列的转变就有可能会出现不同的异常类型
异常处理
语法:try与except
工作原理:
将有可能出现异常的代码块放入try下,try会在遇到一个异常之后然后与except要捕捉的异常做匹配,若匹配成功则执行except下的子代码,若没有匹配成功则仍然抛出异常然后结束整个程序。
try: print('start------>') x=1 print(y) # 遇到NameError异常然后与except匹配 l=[] print(l[3]) # 遇到IndexError异常然后与except匹配 d = {'a': 1} print(d['b']) # 遇到KeyError异常然后与except匹配 except NameError: print('变量没有被定义') except IndexError: print('索引值超出范围') # 若匹配成功则运行except下的子代码 except KeyError: # 可以有多分支的except print('Key不存在字典内') print('---------ending')
同时捕捉多个异常与万能异常:
多个异常:
try: print('start------>') x=1 print(y) l=[] print(l[3]) d = {'a': 1} print(d['b']) except (NameError, KeyError, IndexError): 将要捕捉的异常使用一行进行匹配,代码简洁 print('变量或Key或索引出现错误')
万能异常:Exception
try: print('start------>') x=1 print(y) l=[] print(l[3]) d = {'a': 1} print(d['b']) except Exception: 使用Exception可以匹配捕捉所有异常类型 print('出错了~')
as
try: print('start------>') x=1 print(y) except NameError as e: 将匹配成功的异常的值赋值给as后的变量 print('变量名没有被定义', e) 打印e则会打印出相应的异常值
输出结果:
变量名没有被定义 name ‘y’ is not defined
总结:
我们在处理异常时一定要谨记:一定不要将所有的代码都放入try下然后使用万能异常捕捉,这样即便程序不会报错但终究不是我们要达到的目的,我们最终的目的是发现异常并解决异常然后使我们的程序运行起来没有异常,异常的结果是来帮助我们发现并及时的更正错误,而不是要去掩盖与逃避错误,所以我们在使用异常时一定要将自己不太确定是否会出现异常的代码放入try的下面,使用except时也要注意,只要不是出现所有异常都必须要运行的代码,我们更应该使用具体的异常类型来进行捕捉并执行相应的代码。以便于我们区分具体出现异常的代码并做出更正!
try与except与else
在try与except后加入else,else则会在try中没有任何异常的情况下执行其子代码块,且else不能加在try与except之前,也不能与try单独使用
try: print('start------>') x=1 print(y)
# else: # print('无任何异常') 错误示范,语法异常
except NameError as e: print('变量名没有被定义', e) else: print('无任何异常')
try与except与finally
在try与except之后加入finally,finally会在无论try中有没有异常以及无论except是否捕捉到异常的情况下执行其子代码。
try:
f = open('a.txt', 'w', encoding='utf-8')
f.readline() w模式下打开的文件若读则会出现异常然后与except进行匹配
f.close()
except IOError as e: 若匹配成功则运行子代码,若不成功则依然抛出异常结束程序,此时的文件f依然没有关闭
print('变量名没有被定义', e)
finally:
f.close() finally作为一个无论任何情况下都会执行的对象,则可以实现无论有无异常依然会顺利关闭文件从而回收系统资源
异常处理之主动触发异常
我们刚才所学到的都是系统检测之后满足某个条件之后自动触发的异常,而主动触发异常则是在语法异常与逻辑异常之外的一种异常,是我们自己定制的一种异常,也可以说我们给自己定制的一个硬性的语法,不按照这种方式进行操作就会抛出异常然后终止整个程序。
需要了解的是,我们所主动触发的异常虽然是由我们定制的,但其异常类型必须是继承了Exception类的类型。
关键字:raise + 继承了Exception的类
class People: def __init__(self, name, age): if not isinstance(name, str): raise TypeError('用户名必须为字符串') 主动抛出Type类型的异常并告诉使用者异常值 if not age.isdigit(): raise TypeError('年龄必须为整数') p = People('egon','asd')
异常处理之断言
在Pycharm中可以将断言理解为断定的意思,断定则是在确定了某件事之后才进行某件事,例如我们的if,while等等,都是在条件成立之后才执行的某些事,而断言的基本原理与它们是一样的,断言更准确的则是拿到上层代码的运行结果来进行判断,在满足某种条件后才执行以后的代码,断言只是一个判断,没有任何子代码,使用断言就好比在程序之中设置了一层关卡,而这层关卡又是基于上面代码的运行结果而来的。
关键字:assert
stu = ['egon', 'alex', 'wpq'] if len(stu) <= 0: raise TypeError('列表为空') 使用if与raise完成断言功能 assert len(stu) > 0 使用断言的关键字完成功能 print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1]) print(stu[1])
异常处理之自定义异常
基于我们之前学过的类与对象,我们可以知道万物都是对象,而异常也不例外
所有异常类型都是继承了一个基类而产生的,即我们BaseException
那么既然异常也是一个类,那我们其实就可以自己定义一个异常类
而这个异常类大多则是由于BaseException中的异常类型满足不了你的时候才会定义的
而我们定义的异常类依然需要继承所有异常类型的基类,也就BaseException类
如下:
class GGG(BaseException): 定义一个新的异常类型,继承所有异常类型的基类BaseException def __init__(self, msg, user): 为异常对象初始化属性 self.msg = msg self.user = user def __str__(self): 设置打印格式 return '<%s:%s>' % (self.msg, self.user) raise GGG('GG失败', 'klf') 此处抛出自定义的异常等同于产生并打印对象,打印对象则会直接打印__str__的返回值