一、什么是异常
程序在运行过程之中,不可避免的出现一些错误,比如:使用了没有赋值的变量、使用了不存在的索引、除 0 等等。这些错误在程序中,我们称之为异常。程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行。
二、异常的传播
当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会继续传播。如果函数中不会对异常进行处理,,则异常会继续向函数调用处传播。如果函数调用处处理了异常,则不再传播,如果没有则继续向调用处传播。直到传递到全局作用域(主模块),如果依然没有处理,则程序终止,并显示异常信息。
当程序运行过程中出现异常以后,所有的异常信息会被保存在一个专门的异常对象,而异常传播时,实际上就是异常对象抛给了调用处。比如,ZeroDivisionError 类的对象专门用来表示除 0 的异常,NameError 类的对象专门用来处理变量错误的异常。在 Python 中提供了多个异常对象。
python
def fun1():
a = 10 / 0
def fun2():
fun1()
def fun3():
fun2()
fun3()
三、异常处理机制
程序运行时出现异常,目的并不是让程序直接终止。Python 是希望在出现异常时,我们可以编写代码来对异常进行处理。遇到异常时,Python 中有两种处理机制。
3.1、try...except机制
在 Python 中,提供 try...catch 语句捕获并处理异常。在使用时,把可能产生异常的代码放在 try 子句中,把处理结果放在 except 子句中。这样,当 try 子句中的代码块出现异常时,就会执行 except 语句块中的内容。如果 try 语句块中代码没有异常,那么 except 语句块不会执行。这样我们就可以通过代码来处理异常,避免因为一个异常导致整个程序的终止。
我们还可以在原有的基础上在添加一个 else 子句,用于指定当 try 语句块中没有出现异常时要执行的语句块。该语句块中的内容当 try 语句中发现异常时,将不被执行。
我们还可以在添加一个 finallty 子句。该子句中的代码无论是否发生异常都会被执行。
python
try:
代码块(可能出现异常的代码)
except [异常名 [as 异常对象名]]:
代码块(出现错误以后的处理方式)
[else:
代码块(没出现时要执行的语句)]
[finally:
代码块(无论是否出现异常,该子句都会执行)]
如果 except 后面不跟任何内容,则此时它会捕获所有的异常。
python
print("异常处理之前")
try:
# try中放置的是可能错误的代码
print(10/0)
# 如果except后不跟任何内容,此时它会获取所有的错误
except:
# except中放置的是出现以后的处理代码
print("出现异常")
# 这是一个可选的结构,表示没有出现异常要执行的代码
else:
print("程序正常异常,没有错误")
# 这是一个可选结构,表示无论是否出现异常,最后都要执行的语句
finally:
print("无论是否出现异常,该子句都会执行")
print("异常处理之后")
如果 except 后面跟者异常类型,那么该类型对应的异常。我们还可以在在异常类后面跟着一个 as xxx,此时 xxx 就是异常对象。
python
try:
# try中放置的是可能错误的代码
print(10/0)
print(a)
1 + "hello"
# 如果except后不跟着异常的类型,那么它只会捕获该类型对应的异常
# 可以在异常类后面跟着一个 as xxx,此时xxx就是异常对象
except NameError as e:
# except中放置的是出现以后的处理代码
print("出现NameError")
print(e)
except ZeroDivisionError as e:
# except中放置的是出现以后的处理代码
print("出现ZeroDivisionError")
print(e)
# Exception 是所有异常类的父类
# 如果except后跟的是 Exception,它会捕获所有的异常
except Exception as e:
print("未知异常")
print(e)
在使用 try...except语句捕获异常时,如果在 except 后面不指定异常名称,则表示捕获全部异常;
在使用 try...except语句捕获异常时,当程序出现异常并处理完后,程序继续执行;
我们可以在 except 语句后面使用一对小括号将可能出现的异常名称括起来,多个异常之间使用逗号分隔。
3.2、raise机制
如果某个函数或方法可能会产生异常,但不想在当前函数或方法中处理这个异常,则可以使用 raise 语句在函数或方法中抛出异常。
python
raise [异常类型名[异常描述]]
如果异常类型名为可选参数,它用于指定抛出的异常名称以及异常信息的相关描述。如果省略,就会把当前的错误原样抛出。异常描述也可以省略,如果省略,则在抛出异常时,不附带任何描述信息。
python
def div(a,b):
if b == 0:
# raise用于向外部抛出异常
# 后面可以根一个异常类,或异常类的对象
raise ZeroDivisionError("除0异常")
return a/b
print(div(10,0))
四、自定义异常类
我们也可以自定义异常类,只需要创建一个类继承 Exception 类即可。
python
class MyException(Exception):
pass