Python全栈(一)基础之15.异常处理

一、异常的简介

1.异常定义

程序在运行过程中不可避免会出现一些错误,比如使用了没有被赋值过的变量、除0、使用了不存在的索引等等。
如执行print(a),会抛出NameError: name 'a' is not defined
执行print(1/0),会抛出ZeroDivisionError: division by zero
这些错误在程序中即称为异常。
程序在运行过程中一旦出现异常会导致程序立即终止,异常后面的代码都不会执行。

2.处理异常

程序出现异常,目的不是要程序立即终止;
Python中设置异常的目的时再出现异常时,编写代码对异常进行处理。
处理异常语法:try_except_else语句

try:
    代码块(可能出现错误的语句)
except:
    代码块(出现错误以后的处理方式)
else:
    代码块(没有错误时要执行的语句)

如,在try代码块中没有错误时,

print('Python')
try:
    print(1/1)
except:
    print('Error in Try')
print('hello')

结果为,

Python
1.0
hello

在try代码块中有错误时

print('Python')
try:
    print(1/0)
except:
    print('Error in Try')
print('hello')

打印

Python
Error in Try
hello

后边有else语句时且try代码块中没有错误时,

print('Python')
try:
    print(1/1)
except:
    print('Error in Try')
else:
    print('No error in Try')
print('hello')

结果为

Python
1.0
No error in Try
hello

后边有else语句时且try代码块中有错误时,

print('Python')
try:
    print(1/0)
except:
    print('Error in Try')
else:
    print('No error in Try')
print('hello')

打印

Python
Error in Try
hello

二、异常的传播

当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再传播;
如果函数中没有对异常进行处理,则异常继续向函数调用处传播。
如,


def fn():
    print('hello.......')
    print(1/0)
fn()

会出现两次报错,

Traceback (most recent call last):
  File "xxx/Demo.py", line 16, in <module>
    fn()
  File "xxx/Demo.py", line 14, in fn
    print(1 / 0)
ZeroDivisionError: division by zero

对异常进行处理后,

def fn():
    print('hello.......')
    try:
        print(1 / 0)
    except:
        pass

fn()

打印hello.......
如果函数调用处处理了异常,则不再传播;
如果没有处理则继续向调用处传播;
直到传递到全局作用域,如果依然没有处理,则程序终止,并显示异常信息。

def fn():
    print('in fn')
    print(1/0)

def fn2():
    print('in fn2')
    fn()

def fn3():
    print('in fn3')
    fn2()

fn3()

打印

in fn3
in fn2
in fn
Traceback (most recent call last):
  File "xxx/Demo.py", line 34, in <module>
    fn3()
  File "xxx/Demo.py", line 32, in fn3
    fn2()
  File "xxx/Demo.py", line 28, in fn2
    fn()
  File "xxx/Demo.py", line 24, in fn
    print(1/0)
ZeroDivisionError: division by zero

即抛出了ZeroDivisionError,这是一个异常对象

三、异常对象

当程序运行过程中出现异常以后,所有的异常信息会被专门保存到一个异常对象中;
异常传播时,实际上就是异常对象抛给了调用处。
如NameError类专门处理变量的错误。

print('Before Exception')
try:
    print(a)
    print(1/0)
except:
    print('Handling Exception')
print('After Exception')

打印结果为

Before Exception
Handling Exception
After Exception

except后增加异常对象时,

print('Before Exception')
try:
    print(a)
    print(1/0)
except NameError:
    print('NameError Exception')
print('After Exception')

结果为

Before Exception
NameError Exception
After Exception

但是当except语句中的异常对象未与try语句块中的异常类型匹配时,

print('Before Exception')
try:
    print(1/0)
except NameError:
    print('NameError Exception')
print('After Exception')

打印

Traceback (most recent call last):
  File "xxx/Demo.py", line 37, in <module>
    print(1/0)
ZeroDivisionError: division by zero

出现报错,意即except后的异常对象只能捕获与之对应的异常,不能捕获其他异常。

print('Before Exception')
try:
    print(1/0)
except NameError:
    print('NameError Exception')
except ZeroDivisionError:
    print('ZeroDivisionError Exception')
print('After Exception')

打印

Before Exception
ZeroDivisionError Exception
After Exception

即此时捕获到ZeroDivisionError,try语句块后边可以同时跟多个except语句块,来捕获多个异常。
如果except后面不跟任何内容,此时会捕获到所有的异常;
如果except后面跟着一个异常类型,此时只会捕获该类型的异常。
Exception是所有异常类型的父类;
如果except后跟的是Exception,它会捕获到所有的异常。

print('Before Exception')
try:
    print(a)
    print(1/0)
except Exception:
    print('in Exception')
print('After Exception')

结果为

Before Exception
in Exception
After Exception

即Exception可以捕获所有的异常,并且可将异常对象赋值给另一个对象,来进行打印以识别异常类型。

print('Before Exception')
try:
    print(1/0)
except Exception as e:
    print(e,type(e))
print('After Exception')

打印

Before Exception
division by zero <class 'ZeroDivisionError'>
After Exception

可据此得出异常内容和异常类型。

finally语句

无论是否出现异常都会执行。
没有异常时,

print('Before Exception')
try:
    print(1/1)
finally:
    print('Hello')
print('After Exception')

打印结果为,

Before Exception
1.0
Hello
After Exception

有异常但无except语句块时,

print('Before Exception')
try:
    print(1/0)
finally:
    print('Hello')
print('After Exception')

打印结果为,

Traceback (most recent call last):
  File "xxx/Demo.py", line 37, in <module>
    print(1/0)
ZeroDivisionError: division by zero
Before Exception
Hello

有异常且有except语句块时,

print('Before Exception')
try:
    print(1/0)
except:
    print('In Exception')
finally:
    print('Hello')
print('After Exception')

打印

Before Exception
In Exception
Hello
After Exception

显然,有无异常时均执行了finally语句块中的语句。
当try语句块中有异常时,如果没有except语句,先执行finally语句块,再回到try语句块报错;
如果有except语句块,则先执行except语句块,再执行finally语句块。

异常的完整语法:

try:
    代码块(可能出现错误的语句)
except 异常类型1 as 异常名:
    代码块(出现错误以后的处理方式)
except 异常类型2 as 异常名:
    代码块(出现错误以后的处理方式)
except 异常类型3 as 异常名:
    代码块(出现错误以后的处理方式)
...
else:
    代码块(没有错误时要执行的语句)
finally:
    代码块(是否有异常都会执行)

四、自定义异常对象

1.抛出异常

使用raisre语句来抛出异常,后面需要跟一个异常类或异常实例。

def add(a,b):
    r = a + b
    return r

print(add(-1,2))

打印结果为1
现在定义函数只计算正数,如果a、b中有负数,就向调用处抛异常。

def add(a,b):
    if a < 0 or b < 0:
        raise Exception
    r = a + b
    return r

print(add(-1,2))

此时会报错

Traceback (most recent call last):
  File "xxx/Demo.py", line 48, in <module>
    print(add(-1,2))
  File "xxx/Demo.py", line 44, in add
    raise Exception
Exception

同时,可自定义异常类型,便于直观得出异常信息

def add(a,b):
    if a < 0 or b < 0:
        raise Exception('NegativeError')
    r = a + b
    return r

print(add(-1,2))

此时为

Traceback (most recent call last):
  File "xxx/Demo.py", line 48, in <module>
    print(add(-1,2))
  File "xxx/Demo.py", line 44, in add
    raise Exception('NegativeError')
Exception: NegativeError

抛出异常的目的,时告诉调用者调用时可能出现问题,以便自己进行处理。

2.定义异常类

只需要继承Exception,就可以了。

class MyError(Exception):
    pass

def add(a,b):
    if a < 0 or b < 0:
        raise MyError('NegativeError')
    r = a + b
    return r

print(add(-1,2))

结果为

Traceback (most recent call last):
  File "xxx/Demo.py", line 53, in <module>
    print(add(-1,2))
  File "xxx/Demo.py", line 49, in add
    raise MyError('NegativeError')
__main__.MyError: NegativeError

抛出了MyError异常,并给出了异常提示信息。
小编那么拼,赞一个再撤!
公众号二维码
大家也可以关注我的公众号:Python极客社区,在我的公众号里,经常会分享很多Python的文章,而且也分享了很多工具、学习资源等。另外回复“电子书”还可以获取十本我精心收集的Python电子书。

发布了51 篇原创文章 · 获赞 184 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/CUFEECR/article/details/103226489