Python中异常处理
1、异常 Exception
错误Error
逻辑错误:算法写错了,加法写成了减法。
笔误:变量名写错了,语法错误。
错误可以避免的
异常Exception
本身就是意外情况。一些意外,导致程序无法正常的执行下去。
是不可避免的。
错误和异常
在高级编程语言中,一般都有错误和异常的概念,异常是可以捕获的并被处理的,但是错误是不能捕获的。
with open('test') as f:
pass
错误信息:
Traceback (most recent call last):
File "C:/Users/WCL/PycharmProjects/untitled1/package/test1/异常处理.py", line 1, in <module>
with open('test') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'test'
def 0A():
pass
File "C:/Users/WCL/PycharmProjects/untitled1/package/test1/参数检查.py", line 142
class typeassert
^
SyntaxError: invalid syntax
一个健壮的程序,尽可能的避免错误。
尽可能的捕获,处理各种异常。
2、产生异常
产生:raise语句显示的抛出异常。
Python解释器自己检测到异常并引发他。
def foo():
print('-----')
def bar():
print(1/0)
bar()
print('after')
foo()
def bar():
print('+++++++++++++')
raise Exception('Exc')
print('+-+-+-+-+-+')
bar()
程序会在异常抛出的地方中断执行,如果不进行捕获,就会提前结束程序。
raise语句
raise后什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛出类型异常。很少利用的方式。
raise
后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化。
异常必须出自BaseException
sys.exc_info()查看异常所在的元素。
sys.exc_info() ,后面是个元组。(异常类、异常对象,trackback)
3、异常捕获
try:
待捕获异常的代码块
except[异常类型]:
异常的处理代码块
try:
print('++++++++++++++++')
c = 1/0
print('----------------')
except:
print('catch the exception')
print('outer')
++++++++++++++++
catch the exception
Outer
执行到c = 1/0时候产生异常并抛出,由于使用了语句捕捉这个异常,所以产生异常位置后面的语句将不再执行了,转而执行对象except以外的语句。
2)捕获指定类型的异常。
try:
print('++++++++++++++++')
c = 1/0
print('----------------')
except ArithmeticError:
print('catch the ArithmeticError:')
print('outer')
++++++++++++++++
catch the ArithmeticError:
Outer
特别关心的异常放在最上面。
自己定义的异常。
Exception 非退出性异常。
捕获原则:
4、异常类即继承层次
def exc_hierarchy(exc=BaseException, level=-1):
name = exc.__name__
if level == -1:
print(name)
else:
print("{} +-- {}".format(' ' * level, name))
for sub in exc.__subclasses__():
exc_hierarchy(sub, level+1)
BaseException
+-- Exception
+-- StopAsyncIteration
+-- OSError
+-- BlockingIOError
+-- FileNotFoundError
+-- IsADirectoryError
+-- TimeoutError
+-- InterruptedError
+-- ProcessLookupError
+-- NotADirectoryError
+-- ConnectionError
+-- BrokenPipeError
+-- ConnectionAbortedError
+-- ConnectionRefusedError
+-- ConnectionResetError
+-- UnsupportedOperation
+-- FileExistsError
+-- ChildProcessError
+-- PermissionError
+-- ArithmeticError
+-- FloatingPointError
+-- OverflowError
+-- ZeroDivisionError
+-- AttributeError
+-- SyntaxError
+-- IndentationError
+-- TabError
+-- SystemError
+-- CodecRegistryError
+-- ImportError
+-- ZipImportError
+-- BufferError
+-- LookupError
+-- IndexError
+-- KeyError
+-- CodecRegistryError
+-- NameError
+-- UnboundLocalError
+-- TypeError
+-- error
+-- StopIteration
+-- AssertionError
+-- Warning
+-- UserWarning
+-- DeprecationWarning
+-- UnicodeWarning
+-- PendingDeprecationWarning
+-- ImportWarning
+-- RuntimeWarning
+-- ResourceWarning
+-- SyntaxWarning
+-- BytesWarning
+-- FutureWarning
+-- Error
+-- ValueError
+-- UnicodeError
+-- UnicodeEncodeError
+-- UnicodeDecodeError
+-- UnicodeTranslateError
+-- UnsupportedOperation
+-- ReferenceError
+-- RuntimeError
+-- RecursionError
+-- NotImplementedError
+-- _DeadlockError
+-- MemoryError
+-- EOFError
+-- GeneratorExit
+-- KeyboardInterrupt
+-- SystemExit
5、BaseException及子类
1)BaseException所有内建异常类的基类是BaseException。
2)SystemExit
sys.exit()函数引发的异常,异常不捕获处理,就直接交给Python解释器,解释器退出。
import sys
print('++++')
sys.exit(1)
print('sysexit')
print('-----')
++++
Process finished with exit code 1
未进行捕获的情况下,
解释器直接退出了。
import sys
try:
print('++++')
sys.exit(1)
except SystemExit:
print('sysexit')
print('-----')
++++
sysexit
-----
捕获的情况下正常执行,且被捕获。
3)Keyboardinterrupt
对应捕获用户中断的行为 Ctrl + c
6、Exception及子类
Exception是所有内建的,非系统退出的异常的基类,自定义异常应该定义继承自它。
1)SyntaxError语法错误,Python中也归到Exception类中,但是语法错误是不可被捕获的。
2)ArithmeticError所有算数计算引发的异常,其子类有除零异常等。
3)LookupError 使用映射的键或者序列的索引无效是引发的异常的基类:indexerror keyerror
4)自定义的异常:从Exception继承的类。
7、异常的捕获
Except可以捕获多个异常。
捕获的原则:捕获是从上到下依次比较,如果匹配,则执行匹配的except语句块。
如果被一个except语句块捕获,其他的except就不会再次捕获了。
如果没有任何一个except语句捕获到这个异常,则该异常向外抛出。
捕获的原则,从小到大,从具体到广泛。
8、as子句
被抛出的异常,应该是异常的实例,获得这个对象的话,使用as子句。
class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
try:
raise MyException
except MyException as e:
print(11111111)
print('{}{}'.format(e.code,e.message))
except Exception as e:
print('{}'.format(e))
__init__() missing 2 required positional arguments: 'code' and 'message'
raise后面有特定的参数,如果没有的话就是无参形式。
9、finally 子句
Finally 最终,即最后都会是要一定执行的。try.....finally不管有没有异常都会执行。
Finally中一般都是放置资源的清理,释放工作的语句。
也可以在finally中再次捕获异常。
10、finally执行时机
def foo():
try:
return 3
finally:
print('finally')
print('---')
print(foo())
尽管函数有return返回语句,但是finally语句还是要执行的,最后才返回return语句。
拿的值是最后一个return。
11、异常传递
def foo1():
return 1/0
def foo2():
print('foo2 ----')
foo1()
print('foo2++++')
foo2()
foo2调用了foo1,foo1产生的异常传递到了foo2中
异常总是向外层抛出,如果外层没有处理这个异常,就会继续向外抛出,如果内层捕获并处理了异常,外部就不能捕获的到了。
如果到了最外层还是没有被处理,就会中断异常所在的线程的执行。
import threading
import time
def foo1():
return 1/0
def foo2():
time.sleep(3)
print('foo2----')
foo1()
print('foo2++++')
t = threading.Thread(target=foo2)
t.start()
while True:
time.sleep(1)
print('Everything OK')
if t.is_alive():
print('live')
else:
print('dead')
未进行捕获异常,异常抛出直接中断了线程。
sys.exc_info() ,后面是个元组。(异常类、异常对象,trackback)
12、try 的嵌套
try:
try:
ret = 1/0
except KeyError as k:
print(k)
else:
print('ok')
finally:
print('finally')
except:
print('c ok')
finally:
print('fin')
内部捕获不到异常,会向外层传递异常。
但是如果内层有且有finally而且其中有return、break语句,否则就不会继续往外抛出异常。
def foo():
try:
ret = 1/0
except KeyError as F:
print(k)
finally:
print('finally a ')
return #异常直接被丢弃
try:
foo()
except:
print('+++++')
finally:
print('-------')
有return语句,异常直接被丢弃。
13、异常的捕获时机
1)立即捕获
需要立即返回一个明确的结果
def parse_int(s):
try:
return int(s)
except:
return 0
print(parse_int('s'))
被return直接返回0
2)边界捕获
封装产生了边界。
(1)一个模块,用户调用了这个模块的时候捕获异常,异常内部不需要捕获,处理异常,一旦内部处理了,外部调用者无法感知异常了
(2)Open函数,出现的异常交给调用者处理,文件存在,就不用创建了,看是否修改修改还是删除。
(3)自己写了一个类,使用open函数,但是文件出现异常不知道如何处理,就继续向外层抛出,一般来说最外层也是边界,必须处理异常,如果不处理的话,线程就会推出。
14、else子句
else子句,没有异常发生,则执行。
try:
ret = 1/0
except ArithmeticError as e:
print(e)
else:
print('ok')
finally:
print('fin')
####division by zero
###fin
15、总结
try:
<语句> #运行别的代码
except<异常类>:
<语句> #捕获某种类型的异常
except<异常类> as <变量名>:
<语句> #捕获某种类型的异常并获得对象
else:
<语句> #如果没有异常发生
finally:
<语句> #推出try的时候总会执行
try的工作原理
(1)如果try中语句执行时候会发生异常,搜索except子句,并执行第一个匹配该异常的except子句。
(2)如果try中语句执行时发生异常,却没有匹配except子句,异常将被递交到外层的try,如果外层不处理这个异常,异常将继续向外层传递,如果都不处理该异常,则会传递到最外层,如果还没有处理,就会终止异常所在的线程。
(3)如果try执行时候没有异常,将执行else子句中的语句。
(4)无论try中是否发生异常,finally子句最终都会执行。