一.什么是异常
我们需要明白的是异常的发生不是因为我们代码写错了,我们的代码是可以编译的,但是在运行时产生了一个错误,这个错误是一个异常情况,计算机不能处理这个异常情况,就产生了一个异常。
总结一下异常发生:1.不是代码的问题。 2.比如想要打开的文件不存在,想要处理的问题输入了一个异常值等等都会产生一个异常。
二.如何处理异常
对于异常的处理一般有两种方法。
第一种方法:增加新的逻辑,去处理这个异常,比如打开的文件不存在,我们就增加一个判断语句,判断文件是否存在。但是如果有更多的问题出现,那么就需要增加更多的逻辑,我们可以知道这种方法并不高明。
第二种方法:使用try语句处理异常,事实上,python允许我们在异常发生时捕获异常,这么就给我们提供了一个机会,可以从这个错误中恢复,最重要的是可以避免崩溃,这样在面对大多数运行时错误我们的程序都是健壮的。
那么不知道你们有没有这样的疑问,为什么try语句就能做到捕获异常,还能从这个错误中恢复呢,这是因为在异常控制流期间,python会先尝试运行我们的代码,如果我们的代码发现有问题,就会执行恢复代码,然后继续正常执行我们的代码
下面用图来比较一下正常控制流和异常控制流的区别:
正常控制流:(发生异常,代码就不能继续执行)
异常控制流:(发生异常,捕获异常,执行恢复代码,异常得到处理,继续执行)
三.try…except机制:
try语句允许错误发生,如果针对每一个可能的错误都编写代码,这无疑是一个巨大的工程,而使用try语句,我们操心的更少,编写代码的任务也会轻松很多。
四.下面用一个读取文件的例子去使用try语句。
我们要读取一个文件,文件内容如下:
python读取文件的机制是按行读取的,一次会达到一个数据行。
data = open('test.txt')
for each in data:
(role, line_spoken) = each.split(':', 1)
print(role, end='')
print('said:', end='')
print(line_spoken, end='')
data.close()
1.我们没有创建test.txt文件,于是就出现了一个异常:No su’ch file or directory
2.使用try…except.
注意上面写的要保护的代码,我们要找出要保护的代码,在这里就是所有的代码。
修改代码如下:
try:
data = open('test.txt')
for each in data:
(role, line_spoken) = each.split(':', 1)
print(role, end='')
print('said:', end='')
print(line_spoken, end='')
data.close()
except IOError as err:
print("File error:" + str(err))
运行,可以看到代码正常执行了,并且输出了except的内容(处理特定异常)
这里的as 是给异常对象取一个名字,str(err),把异常对象强制转换成字符串。不然会发生TypeError.
但是这里我们需要注意的一点是如果我们只是读取一个文件,发生IOError确实很烦人,不过一般还不算危险,因为我们的数据还在文件中,向文件中写数据就完全不同了,如果在文件关闭前需要处理一个IOError,所写的数据有可能被破坏
例子如下:
test = []
try:
data=open('test.txt')
for each in data:
test.append(each)
data.close()
except IOError as err:
print("File error:" + str(err))
try:
test_file = open('test_data.txt','w')
print(test, file=test_file)
test_file.close()
except IOError as err:
print("File error:" + str(err))
先讲一下上面的涉及知识点:
1.open函数常用形式open(file, mode=‘r’)。
2.open函数默认使用模式 r 表示读。mode是可选参数,但在函数中给参数赋一个值,该参数变为可选参数。w表示只用于写,wb以二进制格式打开一个文件只用于写入。
3.file,文件路径,必选路径(可以是相对路径和绝对路径),绝对路径就是在写路径时把位置都写清楚,如下写法是绝对路径:data=open(‘C:/Users/ASUS/Desktop/test.txt’)(注意在windows系统下,是正斜杆,不是反斜杠)
data=open(‘test.txt’),该写法是相对路径,对于相对路径,如果前面一个目录也没有,需要让test.txt与test.py在一个目录下才可以这样写,也可以在test.py当前目录下再创一个文件夹,把test.txt放进该文件夹中,如创建test目录,则写法变为 data=open(‘test/test.txt’),相对路径只有这两种,要么在同一个目录,要么在.py文件目录下的子目录中。
4.使用print把指定的列表写入指定的文件中。
5.写入效果如下,是一个列表。
6.open函数并非只能访问文本文件,open可以访问任何形式的文件,在访问非文本格式文件(二进制文件)的时候,访问模式通常加上‘b’(即二进制模式:‘rb’或‘wb’),但并不必须,依情况而定
我上面说了那么多其实就是想引入一个finally:
想一下,如果发生上面的情况该怎么办,这种情况文件也没有关闭,并且数据也有可能被破坏。
这里需要一种策略,保证不论是否发生IOError都会运行某些代码,在代码上下文,我们希望不论发生什么都要确保关闭文件。
于是我们可以使用finally.
代码如下:
用finally扩展try:
test = []
try:
data=open('C:/Users/ASUS/Desktop/test.txt')
for each in data:
test.append(each)
data.close()
except IOError as err:
print("File error:" + str(err))
try:
test_file = open('test_data.txt','w')
print(test, file=test_file)
except IOError as err:
print("File error:" + str(err))
finally:
test_file.close()
于是无论如何文件都会关闭了,finally的作用就是这样。通过把文件关闭代码移入到finally组中,可以减少数据被破坏的可能性。
那么会不会有其他错误呢,如果打开一个不存在的文件,在finally中将文件关闭会发生什么?
修改代码如下:
test = []
try:
data=open('miss.txt')
for each in data:
test.append(each)
data.close()
except IOError as err:
print("File error:" + str(err))
try:
test_file = open('test_data.txt','w')
print(test, file=test_file)
except IOError as err:
print("File error:" + str(err))
finally:
test_file.close()
可以发现这个错误‘data’ is not defined.
这是因为文件不存在,数据对象未创建,这样就不可能在数据对象上调用close方法,那么我们又该怎么办呢?
修改代码如下:
test = []
try:
data=open('miss.txt')
for each in data:
test.append(each)
data.close()
except IOError as err:
print("File error:" + str(err))
try:
test_file = open('test_data.txt','w')
print(test, file=test_file)
except IOError as err:
print("File error:" + str(err))
finally:
if 'data' in locals():
data.close()
locals函数返回当前作用域中定义的所有名的一个集合。
这样就没有其他的异常了。只会显示错误信息。
说了那么多,终于说完了,既然这么麻烦,打开文件有没有什么更好的办法。
当然有,可以使用with处理文件。
test = []
try:
data=open('miss.txt')
for each in data:
test.append(each)
data.close()
except IOError as err:
print("File error:" + str(err))
try:
with open('test_data.txt','w') as test_file:
print(test, file=test_file)
except IOError as err:
print("File error:" + str(err))
上面的代码跟使用finally的功能一样,当然with的用法很多,需要单独拿出来总结。
五.try语句的其他各种形式:
当然except可以写多个,格式如下:
try:
要保护的代码。
except <异常名字>:
错误恢复代码(如果发生这个异常就执行该except后的错误恢复代码)
except <异常名字>:
错误恢复代码(如果发生这个异常就执行该except后的错误恢复代码)
else:
没有异常运行这断代码,可写可不写,想写就写。
如果except不带任何异常类型,就会捕获所有异常。但是我们并不推荐这么做,因为不知道异常类型。
try:
要保护的代码
except:
错误恢复代码(捕获所有异常)
else:
没有异常执行这段代码
也可以用相同的except处理多种异常类型
try:
要保护的代码
......................
except(Exception1[, Exception2[,...ExceptionN]]]):
发生以上多个异常中的一个,执行这段代码
......................
else:
如果没有异常执行这段代码
写法如下:
try:
要保护的代码
except (IOError, ValueError):
发生以上多个异常中的一个,执行这段代码
还有一个知识点就是raise.
我们可以使用raise语句自己触发异常
触发之后后面的语句不会执行,触发之后然后用except捕获相同的异常类型。具体使用就不总结,今天总结太多了。
还有我们需要知道的是一些常用的异常类型,网上有很多,多看一下就熟悉了。
今天的总结就到这,拜拜。
如果有任何错误,欢迎大佬指正,非常感谢。
转载:https://blog.csdn.net/weixin_45290352/article/details/105774582