Python自学笔记第28篇--异常1
Python自学笔记第28篇--异常1
ZhangCurryPython自学笔记第28篇–异常1
在Python中,我们要捕获异常,来确保程序的正常运行。
什么是异常,异常是错误吗?
第一个知识点:异常和错误傻傻分不清楚
1:什么是错误
首先说下错误,错误一般是指语法错误,也就是书写代码的时候,没有按照Python的语法规则进行书写导致的程序错误。
例如:
if a==1
print(‘这就是语法错误’)
因为Python要求if的结束要以冒号‘:’结尾,你没有在条件语句a==1后面加‘:’的话,Python就看不懂你写的什么东西,于是就会报错。
这样的错误,我们称为语法错误(Syntax Error),报错的时候见到Syntax Error,你就检查一下你的代码是不是语法格式出错了,导致Python认识不了了。
错误一般是你粗心或者对Python语法格式不太熟练的情况下导致的,说白了就是你编写代码的时候写不对导致的,再通俗点就是不会写导致的。错误是可避免的,多练就对了。
2:什么是异常
异常不是语法的错误,一般情况下语法格式没有问题,但是运行过程中出现了意外情况。当然这些意外情况一般是可以预见的。例如,我们生活中用除法的时候,知道除数不能为零。但是我们用python编写了一个除法的代码,提交给用户使用,用户输入两个数,就可以完成除法的运算。示例代码如下:
1 | 被除数=float(input('请输入被除数:')) |
这段代码,语法格式没问题,但是如果用户不小心把除数输入为0的话,就出先了下图的报错信息,导致程序无法往下正常的执行,那就不能输出‘我是大聪明了’。这就是异常。
1 | 请输入被除数:100 |
这个报错信息中出现ZeroDivisionError,这就是除0错误。
异常就是我语法上没错,但是我可能就是逻辑错误,或者资源不足导致程序不能正常执行下去。如果程序出现异常,导致程序无法正常执行,卡出去了,那就太烦了,于是我们要捕获异常。
捕获异常的目的就是让异常不影响程序的正常运行,或者给用户提示,让用户避免输入错误。
下面我们来看一下如何捕获异常
第二个知识点:捕获异常
1:用try-except语句捕获异常(不写异常类型的情况)
1 | try: |
例子:
1 | try: |
当除数为0的时候,输出结果如下:
1 | 请输入被除数:100 |
我们观察这个输出结果,我们虽然捕获了异常–除数不能为0,但是发现依然报错了,说商没有被定义,这是为什么呢?看下图应该就明白了
当我们输入除数为0,它还没来得及给商赋值的时候,就发现异常,直接跳到了except代码块执行了,导致商没有被赋值。所以后面打印商的时候,就会出现商没有被定义,导致错误出现。
这我们就郁闷了,捕获异常,却以报错为代价,程序依然没办法继续执行下去。那怎么办,不慌,往下看。
2:try-except语句和if语句嵌套使用
1 | try: |
try-except语句和if嵌套使用,可以先让if判断除数是不是0,如果是0,就用raise来主动抛出异常,异常类型是:ZeroDivisionError。
下面是除数为0时的输出结果:
1 | 请输入被除数:100 |
raise用法格式如下:
raise 异常类型
这段代码中,执行过程,就是if通过判断,发现异常,用raise抛出异常,并携带异常的详细信息:‘除数不能为0呦’,然后except捕获异常,执行了except的代码块:出错了,请重新输入。
仔细观察这个过程就会发现,except在不加捕获类型的情况下,它虽然接住了raise抛出的异常,同时也忽略了raise携带的异常详细信息,它不管raise是否携带异常详细信息的描述,只要捕获异常,它就执行自己的代码块。
这样有可能会造成捕获用户主动造成的异常,例如while True:无限循环时,用户用CTRL+C想中止循环,用户按住ctrl+c之后,Python会抛出KeyboardInterrupt 异常,以中断当前程序的执行流程。但是如果后面有except这个家伙的话,也就是说,用户想中止程序的执行,可except可不管什么异常,它都捕获,来保证程序的正常运行。所以在某些时候,最好用except+异常类型,来捕获具体的异常类型,并且还可以输出raise抛出异常的具体信息。示例如下:
3:except[具体类型的异常]
1 | try: |
此时输出的结果如下:
1 | 请输入被除数:100 |
except [具体的异常类型] as e:except捕获异常对象后就把它赋值给变量e,而变量e会访问异常的详细信息:除数不能为0呦。
Python自学笔记第29篇–异常2
第一个知识点:多个except代码块
多条语句可能会引发不同的异常,想对每一种异常采用不同的处理方式,就可以在try后面跟多个except。
例如:``
1 | try: |
代码中,如果除数为0,会报出异常,但是也有可能是被除数或者除数输入的是非数字的字符,就会造成ValueError,例如,字母是无法转换成浮点型数据的,而且无法进行算术运算。
第二个知识点:预估到异常可以捕获,预估不到的异常怎么办?
例如:
1 | try: |
代码中:对于非预期的异常,可以用except Exception来捕获非系统类退出的异常。except Exception相比于except不加具体异常类型的捕获,它不会捕获用户主动中断或程序退出的信号。也就是上一篇的无限循环,如果用户按ctrl+c主动中断,那except不加具体异常类型的捕获也会捕获这样的异常,但是except Exception不会。
第三个知识点:既然Exception这么强大,那不管什么异常,都用except Exception不就行了?
Python建议最好使用except 加具体异常类型的捕获,原因如下,看下面代码:
1 | try: |
这段代码中,由于except Exception捕获的过于宽泛,所以一般无法具体指明是哪种异常,这段代码中,编写代码的人把第二行的input输错成inpur,这样就会造成NameError。那except Exception就会捕获这个异常,让用户重新输入。可无论重新输入多少次,它还是会提示用户重新输入。因为代码本身就存在bug–input输错成inpur。所以用except Exception可能会有掩盖代码本身bug的风险。
Python自学笔记第30篇–异常3
第一个知识点:用finally代码块释放资源
有时,try-except语句会占用一些资源,例如打开的文件,网络连接等。这时候需要程序员释放这些资源。finally代码块可以实现这个功能。
它的逻辑就是无论是try代码块的正常结束还是except代码的异常结束,都会执行finally代码块,保证资源的释放。
例如:
1 | try: |
结果如下:
第一种情况是:try代码块正常结束,会执行finally代码块。
1 | 请输入被除数:10 |
第二种情况:except代码块异常结束,也会执行finally代码块
1 | 请输入被除数:10 |
第二个知识点:自定义异常
自定义异常,顾名思义就是:说你错,你就错,不错也错。
Python自定义异常很灵活,让用户可以定义哪些错了,该如何处理。但是必须遵循Python异常处理的流程和方法。所以必须继承异常的Exception类来获得这套流程和方法。
上一段可能有不理解的地方,咱们通过实际的例子来理解一下:
这个例子的背景是用户要注册一个网站,需要输入自己的年龄,但是年龄不能是负数。可是Python内置异常中并没有‘年龄为负数’的专门类。这时候我们就可以自定义,例如定义一个‘无效年龄’的异常。
代码如下:
1 | class 无效年龄(Exception):#自定义异常类型 |
如果输入的年龄是:-1,结果如下:
1 | 请输入你的年龄:-1 |
解释一:这段代码中,首先用‘class 无效年龄(Exception)’来定义异常类型名字为:无效年龄,并且继承Exception类,来保证可以正常使用抛出异常,捕获异常的流程。如果不继承Exception类的话,相当于下面的代码中,raise是不能使用的,try-except也是不能使用的。例如:raise后面必须是BaseException的子类,这里‘无效年龄’继承了Exception类,Exception类又属于BaseException的子类,所以‘无效年龄’类也是属于BaseException的子类。所以要自定义异常的话,必须继承Exception类,才能正常使用捕获异常,抛出异常的流程。
解释二:raise 为抛出异常的关键字,格式如下:
raise[异常类型](异常的详细描述)
解释三:except为捕获异常,格式如下:
except [异常类型] as [变量]:把捕获的异常对象赋值给变量
通过这样的形式,变量可以访问异常类型的详细描述信息了。
解释四:这里Python建议继承的是Exception类,也就是不包含特殊异常的情况。包含所有异常情况的类为BaseException,它是所有异常的根,也就是老祖先。为什么不建议继承Exception,而不建议BaseException大家可以查以下。
上面的代码也可以这样写:
1 | class 无效年龄(Exception):#自定义异常类型 |
如果输入的年龄是:-1,结果如下:
1 | 请输入你的年龄:-1 |
这段代码中,用__init__()方法,初始化异常的属性,当创建一个类的实例的时候,这个方法会自动执行。当代码中的‘raise 无效年龄(age)’执行的时候,相当于先创建一个类实例,并且传入age参数。
super().init(f’年龄{age}无效,必须是整数’),调用父类方法,把age参数传入后,存储到实例中,作为异常的描述信息。
这样在通过‘except 无效年龄 as e’把异常信息捕获并且赋值给变量e。



