我们的程序在运行出错时,就称为异常,出现的异常都会对应一个相应的类。在python程序运行时出现的异常大多是继承自Exception类。在python中不管是什么类的异常都继承自超类(基类/父类)BaseException。BaseException派生出了4个之类:用户中断执行时异常(keyboardinterrupt),python解释器退出异常(systemexit),内置及非系统退出异常(exception),生成器退出异常(generatorexit)。但是一般来说我们在编写代码后运行程序时,遇到最多的就是exception类异常,它内置了众多常见的异常。现在我们去了解比较常见的几个exception类下的异常。
目录
一,Exception异常
1,NameError(属于编译时异常)
该异常产生的原因是因为我们使用了未定义的变量。如下,我们在没有定义一个变量variable1的情况下去打印它:
相信大家也发现了,这种异常根本不需要等到我们去运行程序后才会给我们报错,编译器会在我们错误的代码下面划上红色的波浪线,提示我们该代码有问题。 该类异常为编译时异常,即我们没有运行程序,但是编译器已经给我显示了问题代码的异常。编译时异常还有:对应的模块没有导入但却使用到了该模块等都会出现该异常。
编译时异常我们就先了解上面的这一个,接下来我们去看一下在编译时没有报错,但是在运行时却报错的异常,因为运行时异常才是令人猝不及防的。
2,IndexError(属于运行时异常)
IndexError是程序越界访问时引发的异常。这一类异常最常见于带有索引的数据类型中,如数组,列表,元组等。当我们在遍历这一类的数据时,编译器并不会给我们提示,等到我们去运行程序后,才会给我们报错(index out of range),告诉我们程序不能越界访问,现在我们使用代码来查看一下具体的使用及效果:
# -*- encoding: utf-8 -*-
if __name__ == '__main__':
tuple1=(1,3,8)
for i in range(len(tuple1)+1): # 元组的索引从0开始
print(tuple1[i]) # 会访问到元组索引位置为3的数据,但是元组只有到索引为2的数据。
3,AttributeError(属于运行时异常)
见名知义,该异常是使用对象访问不存在的属性引发的异常。例如现在我们去访问Student类中不存在的属性work_place:
# -*- encoding: utf-8 -*-
class Student:
def __init__(self,name):
self.name=name
if __name__ == '__main__':
student1=Student("张三")
print(student1.name) # 访问学生类中存在的属性name
print(student1.work_place) # 访问学生类中不存在的属性work_place
4,FileNotFoundError(属于运行时异常)
之前我们学习了python中相关的文件操作,也知道了当使用r来打开文件的话,必须确定我们当前的工作目录里面是有该文件存在的,不然就会报错并告诉我们该文件不存在:
5,ZeroDivisionError(属于运行时异常)
ZeroDivisionError:零分区错误,即在两个数相除的时候除数为0。如下:
# -*- encoding: utf-8 -*-
if __name__ == '__main__':
print(1/0)
二,捕获异常
一般来说程序在运行时出现了异常会使我们的程序直接崩溃,如果我们的代码因为一个异常直接崩溃而无法继续执行程序,那么这样无疑是很不友好的,所以这个时候就需要我们去对其进行相应的处理,对于异常的处理有两种,一种使捕获异常,另外一种是直接抛异常。两种处理异常的方式最根本的区别在于要不要显示出对应的异常类型,如果我们在处理异常的时候想要知道是什么异常导致我们的程序崩溃,那么我们可以使用捕获异常的方法,如果不想要知道该异常的类型,只想要处理掉该异常的话,可以直接使用抛异常的方法。
现在我们来了解在python中怎么进行异常的捕获。
python的捕获异常和Java的有所不同,在Java中的捕获异常不需要进行导包操作,但是在python如果想要在对异常进行处理的时候打印出异常栈信息就需要导入traceback模块(看自己喜欢,一般不用也可以。),在语法上也有所不同,Java中的异常捕获语法如下:
public class JavaTest01 {
public static void main(String[] args) {
try{
int result=3/0; // 可能出现异常的代码(被监视的代码)
}
catch(ArithmeticException a){ // 捕获异常后的处理代码1[算术异常]
a.printStackTrace();
}
catch(Exception e){ // 捕获异常后的处理代码2[异常超类]
e.printStackTrace();
}
finally{ // 不管try子句监控的代码是否发生异常,finally子句都会被执行。
System.out.println("程序运行结束");
}
}
}
在python中的逻辑也差不多,但是在语法上就有些许的不同,它也是使用了try子句来包含我们可能出现异常的代码(被监视的代码),但是用来执行捕获后异常后的处理代码得需要放置在expect子句里面,并且,在python中还有else子句(当我们的业务代码执行成功时,执行else从句),即没有异常的处理代码。它也有finally子句,无论如何都执行,即不管try有没有异常,finally都会去执行。一般来说,finally子句多用于预设资源的清理操作,如:关闭文件(这个可以忽略,因为在python中提供了with语句来打开文件,可以自动关闭文件),关闭网络连接,关闭数据库连接等。
# -*- encoding: utf-8 -*-
if __name__ == '__main__':
try: # 包含可能出现异常的代码块(被监视的代码)
with open('haha.txt','r') as f: # 以自动关闭文件的形式打开文件
data=f.read()
except FileNotFoundError as error: # 捕获异常后的执行代码
print("出错了,原因是:",error)
else:
print("文件读取成功") # 没有异常,执行该语句
finally:
print("程序已经运行完成") # 无论成功与否,都执行该语句
当我们需要捕获的代码(被监控的代码)中很多的异常需要捕获时,我们可以直接将except之后的异常类型设置为Exception类型,但是这个时候首先捕获到的异常为try后面的第一个异常,只要捕获到一个异常,就不会再去执行try语句,即无法捕获到后面的异常,如下,我们先将被除数为0的异常写在try子句的前面,文件处理的写在后面,那么,首先显示出来的异常就是被除数为0异常:
现在我们将文件处理的放到前面,我们的文件是不存在的,就会先捕获到文件找不到异常:
三,抛异常
1,raise语句
抛异常相对于捕获异常来说它可以由写代码的我们使用raise语句和assert语句来主动抛出异常,而不仅仅是程序运行后自动触发。一般也叫引发异常。如果通过raise语句抛出异常的话,会由三种格式的raise语句来供我们使用,但是一般用得最多的(最常见的)就是”raise 异常类对象“,直接提供该类型的对象。如下:
# -*- encoding: utf-8 -*-
if __name__ == '__main__':
def div(num1,num2): # 定义一个用来两数相除的方法
if num2==0:
raise Exception("执行在raise中的抛异常:分母为0")
return num1/num2
try:
div(3,0)
except Exception as e:
print("执行在except中的捕获异常:",e)
else:
print("执行了else语句")
finally:
print("程序运行结束(在该程序中无论如何都会执行)")
如上,我们使用了异常类对象来引发异常,形如:raise 异常类对象。该语句可以引发该语句中异常类对象对应的异常。
2,assert语句
assert语句又称为断言语句,格式为:assert 表达式【,异常信息】。该表达式的值为false时触发AssertionError异常,值为true时,不做任何操作。表达式之后可以使用字符串来描述异常信息。
assert语句可以帮助我们在开发阶段体调试程序,以保证程序能够正确运行,接下来我们还是之前的div方法的调用,并使用assert语句:
# -*- encoding: utf-8 -*-
if __name__ == '__main__':
def div(num1,num2): # 定义一个用来两数相除的方法
assert num2!=0,"assert抛异常:分母为0"
try:
print(div(3, 0))
except Exception as e:
print("执行在except中的捕获异常:",e)
else:
print("执行了else语句")
finally:
print("程序运行结束(在该程序中无论如何都会执行)")
四,自定义异常
虽然python提供了很多的内置异常类,但是在实际写代码的时候可能出现的问题难以预料,有时候就需要我们去自定义异常类,以满足当前程序的需要。自定义异常类的方法和Java中一样只需要去继承Exception类或者是Exception之类的类(类名一般是以‘Error’结尾的类)即可。接下来我们使用代码来看一下具体的实现及效果:
# -*- encoding: utf-8 -*-
class CustomExceptionDemo(Exception): # 自定义的异常类
def __init__(self,exception_name,exception_msg): # 该类的名字及打印信息
self.exception_name=exception_name
self.exception_msg=exception_msg
if __name__ == '__main__':
def div(num1,num2): # 定义一个用来两数相除的方法
if num2==0:
raise CustomExceptionDemo("CustomException1","请检查运算,是否存在分母为0的问题")
try:
print(div(3, 0))
except Exception as e:
print("执行在except中的捕获异常:",e)
else:
print("执行了else语句")
finally:
print("程序运行结束(在该程序中无论如何都会执行)")
以上就是python中的异常相关内容,有问题请在评论区留言。