5.异常处理
2021-01-08 本文已影响0人
Stone_説
目录:
1.介绍
2.异常类及继承
3.as、raise、finally介绍
4.异常的传递
5.异常的捕获时机
6.总结
1.介绍
1.1 异常和错误
异常本意就是意外情况,程序没有错误,但是在某些情况下会出现一些意外,导致程序无法正常的执行下去。异常是可以被捕获并被处理,但是错误是不能被捕获的。
例如:
1.open函数操作一个文件,文件不存在,或者创建一个文件时已经存在。
2.访问一个网络文件时,突然断网。
eg:
异常:
with open('test.txt') as f:
pass
Traceback (most recent call last):
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 1, in <module>
with open('test.txt') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
#报了异常FileNotFoundError,打开文件不存在
错误:
def 0A():
pass
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 1
def 0A():
^
SyntaxError: invalid syntax
#函数定义错误,以数字0开头
语法或者逻辑不正确的称为错误。
在语法逻辑正确,运行时出现的“错误”,称之为异常。
1.2 产生异常
Python解释器自己检测到异常并引发它
def foo():
print('before')
print(1/0) # 运行时解释器检测出除零异常
print('after')
foo()
Traceback (most recent call last):
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 6, in <module>
foo()
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 3, in foo
print(1/0)
ZeroDivisionError: division by zero
before
raise语句显式的抛出异常
def foo():
print('before')
raise Exception('my exception') # 程序运行时,raise主动抛出异常
print('after')
foo()
before
Traceback (most recent call last):
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 6, in <module>
foo()
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 3, in foo
raise Exception('my exception')
Exception: my exception
1.3 异常的捕获
try:
逮捕获异常的代码块
except [异常类型]:
异常的处理代码块
def foo():
try:
print('before')
c = 1/0
print('after') # try语句中,异常之后的语句不会被执行
except:
print('error')
print('catch the exception')
foo()
print('****** end ******')
#执行到c = 1/0时,产生异常,使用try...except语句捕获该异常,进而跳转except语句,最后执行try...except之外的语句
before
error
catch the exception
****** end ******
捕获指定类型的异常
def foo():
try:
print('before')
c = 1/0
print('after')
except ArithmeticError: # 可以在except子句之后,指定捕获指定的异常类型
print('error')
print('catch the exception')
foo()
print('****** end ******')
2.异常类及继承
2.1 Python中异常的继承关系图
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
| +-- BufferError
| +-- ArithmeticError
| | +-- FloatingPointError
| | +-- OverflowError
| | +-- ZeroDivisionError
| +-- AssertionError
| +-- AttributeError
| +-- EnvironmentError
| | +-- IOError
| | +-- OSError
| | +-- WindowsError (Windows)
| | +-- VMSError (VMS)
| +-- EOFError
| +-- ImportError
| +-- LookupError
| | +-- IndexError
| | +-- KeyError
| +-- MemoryError
| +-- NameError
| | +-- UnboundLocalError
| +-- ReferenceError
| +-- RuntimeError
| | +-- NotImplementedError
| +-- SyntaxError
| | +-- IndentationError
| | +-- TabError
| +-- SystemError
| +-- TypeError
| +-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
2.2 BaseException及子类
BaseException
所有内建异常类的基类是BaseException
SystemExit
# sys.exit()函数引发的异常,异常不捕获处理,就直接交给Python解释器,解释器退出
import sys
print('before')
sys.exit(1)
print('SysExit')
print('outer')
#程序退出码为1
before
Process finished with exit code 1
#捕获异常
import sys
try:
sys.exit(1)
except SystemExit:
print('SysExit')
print('outer')
# 捕获该异常,退出状态码变为0
SysExit
outer
Process finished with exit code 0
KeyboardInterrupt
# 对应的捕获用户中断行为Ctrl + C
try:
import time
while True:
time.sleep(3)
print('******')
except KeyboardInterrupt:
print('ctrl + c')
print('****** end ******')
#使用键盘的Ctrl + C则该异常将会被捕获
(Python_code) C:\Users\dell\PycharmProjects\pythonProject>python test.py
******
ctrl + c
****** end ******
Exception及子类
#Exception是所有内建的、非系统退出的异常的基类,自定义异常类应该继承自它
SyntaxError语法错误
#Python将这种错误也归到异常类下面的Exception下的子类,但是这种错误是不可捕获的
def foo():
try:
0a = 5
except:
pass
#执行仍然报语法错误SyntaxError
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 3
0a = 5
^
SyntaxError: invalid syntax
ArithmeticError
所有算术计算引发的异常,其子类有除零异常等
LookupError
使用映射的键或序列无效时引发的异常类的基类:IndexError,KeyError
自定义异常类
#从Exception继承的类
class MyException(Exception):
pass
try:
raise MyException()
except MyException:
print('catch the exception')
#捕获自定义类
catch the exception
Process finished with exit code 0
2.3 多种异常捕获
捕获规则:
1.捕获是从上到下依次捕获,如果匹配,则执行匹配的except语句快
2.如果被一个except语句捕获,其他except语句就不会再次捕获
3.如果没有任何一个except语句捕获到,则该异常向外抛出
#自行验证
import sys
class MyException(Exception):
pass
try:
a = 1/0
raise MyException()
open('sff')
sys.exit(1)
except ZeroDivisionError:
print('zero')
except ArithmeticError:
print('Arith')
except MyException:
print('catch my exception')
except Exception:
print('exception')
except:
print('sysexit')
3.as、raise、finally介绍
eg:
class A:
pass
try:
raise 1
except:
print('catch the exception')
catch the exception
Process finished with exit code 0
变式1:
class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
try:
raise MyException
except MyException as e:
print('catch my exception')
except:
print('catch ~~~~')
# 运行时MyException为什么会捕获?
catch ~~~~
Process finished with exit code 0
变式2:
class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
raise MyException
# 直接将MyException抛出,会是TypeError类型的异常
Traceback (most recent call last):
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 7, in <module>
raise MyException
TypeError: __init__() missing 2 required positional arguments: 'code' and 'message'
变式3:
class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
try:
raise MyException
except MyException as e:
print('catch my exception: {} {}'.format(e.code,e.message))
except Exception as e:
print('{}'.format(e))
#运行结果
__init__() missing 2 required positional arguments: 'code' and 'message'
Process finished with exit code 0
变式4:
class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
try:
raise MyException(200,'stone')
except MyException as e:
print('catch my exception: {} {}'.format(e.code,e.message))
except Exception as e:
print('{}'.format(e))
#MyException异常捕获
catch my exception: 200 stone
Process finished with exit code 0
raise语句:
1.raise后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化
2.raise后什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛出异常,不过此种方式很少用。
3.2 finally
不管是否发生异常,try...finally语句块中,不管是否发生异常,finally中子句都会执行
eg:
try:
f = open('test.txt')
except FileNotFoundError as e:
print(e.filename,e.strerror,e.errno)
finally:
print('清理工作')
f.close()
# finally中语句块会被执行
Traceback (most recent call last):
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 7, in <module>
f.close()
NameError: name 'f' is not defined # 抛出NameError异常
test.txt No such file or directory 2
清理工作
Process finished with exit code 1
变式1:解决f的NameError异常
f = None
try:
f = open('test.txt')
except Exception as e:
print('{}'.format(e))
finally:
print('清理工作')
if f:
f.close()
# 给f赋予None,并在finally语句块中再次判断
[Errno 2] No such file or directory: 'test.txt'
清理工作
Process finished with exit code 0
变式2:
try:
f = open('test.txt')
except Exception as e:
print('{}'.format(e))
finally:
print('清理工作')
try:
f.close()
except Exception as e:
print(e)
# 在finally语句块中进行再次捕获,代码返回值为0
[Errno 2] No such file or directory: 'test.txt'
清理工作
name 'f' is not defined
Process finished with exit code 0
3.3 finally执行时机
def foo():
try:
return 3
finally:
return 5
print('finally')
print('==')
print(foo())
# 执行发现,finally中的return语句也会执行
4.异常的传递
4.1 异常传递
def foo1():
return 1/0 # 1.可在此捕获异常
def foo2():
print('foo2 start')
foo1() # 2.可在此捕获异常
print('foo2 stop')
foo2() # 3.可在此捕获异常
# 执行结果如下
Traceback (most recent call last):
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 9, in <module>
foo2()
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 6, in foo2
foo1()
File "C:/Users/dell/PycharmProjects/pythonProject/test.py", line 2, in foo1
return 1/0
ZeroDivisionError: division by zero
foo2 start
Process finished with exit code 1
总结:
1.异常总是向外层抛出,如果外层没有处理这个异常,就会继续向外抛出
2.如果内层捕获并处理了异常,外部就不能捕获到了
3.如果到了最外层还是没有被处理,就会中断异常所在的线程的执行。
4.2 try嵌套
try:
try:
ret = 1/0
except KeyError as e:
print(e)
finally:
print('inner fin')
except:
print('outer catch')
finally:
print('outer fin')
# 执行结果
inner fin
outer catch
outer fin
Process finished with exit code 0
总结:
1.内部捕获不到异常,会向外层传递异常
2.如果内层有finally且其中有return,break语句,则异常就不会继续向外抛出
def foo():
try:
ret = 1/0
except KeyError as e:
print(e)
finally:
print('inner fin')
return
try:
foo()
except:
print('outer catch')
finally:
print('outer fin')
# 执行结果如下:
inner fin
outer fin
Process finished with exit code 0
异常被压制,注意:正常写代码是并不压制异常
5.异常的捕获时机
5.1 立即捕获
需要立即返回一个明确的结果
def parse_int(s):
try:
return int(s)
except:
return 0
print(parse_int('re'))
# 执行结果
0
Process finished with exit code 0
5.2 边界捕获
封装产生了边界
对于一个模块而言,用户调用时,模块内部不想要捕获异常,应该抛出,让外部调用者自己感知,处理
else子句
try:
ret = 10
except ArithmeticError as e:
print(e)
else:
print('OK')
finally:
print('fin')
# 执行结果如下,没有任何异常发生时,则执行else子句
OK
fin
Process finished with exit code 0
6.总结
try:
<语句> # 运行别的代码
except <异常类>:
<语句> # 捕获某种类型的异常
except <异常类> as <变量名>:
<语句> # 捕获某种类型的异常并获得对象
else:
<语句> # 如果没有异常发生
finally:
<语句> # 退出try时总会执行
try工作原理:
1.如果try中语句执行时发生异常,搜索except子句,并执行第一个匹配该异常的except子句
2.如果try中语句执行时发生异常,却没有匹配的except子句,异常将被递交到外层的try,如果外层不处理这个异常,异常将继续向外层传递。
如果都不处理异常,则会传递到最外层,如果还没有处理,就终止异常所在的线程
3.如果在try执行时没有发生异常,如有else子句,可执行else子句中的语句
4.无论try中是否发生异常,finally子句最终都会执行