一 异常和错误1 错误:

逻辑错误: 算法写错了,函数或者类使用出错
语法错误:变量名写错了,语法错误

2 异常(exception)

本意就是意外情况
有一个前提,没有出现上面的错误,也就是说程序写的没有问题,但在某些情况下,会出现一些意外,导致程序无法正常执行下去,异常时不可能避免的,如open函数操作一个文件,文件不存在,或者创建一个文件时已经存在了,或者访问一个网络文件,突然断网了,这就是异常,时意外情况。

3 异常和错误

在高级编程语言中,一般都会有错误和异常的概念,异常是可以捕获的,并被处理,但错误不能被捕获

1 异常

如下

此处是异常,其是Traceback

解决方式如下:

#!/usr/local/bin/python3.6#coding:utf-8try: open('test200') # 以只读的形式打开一个文件,其默认会抛出异常except OSError as e: print (e)

结果如下

2 错误

上述出现的是语法错误导致的问题

#!/usr/local/bin/python3.6#coding:utf-8try: def 0aa(): passexcept: pass

结果如下

此处的错误是无法被捕获的

二 异常及相关类型:1 异常捕获基本

#!/usr/local/bin/python3.6#coding:utf-8try: f=open('test100') #此处是只读方式打开的文件,不存在,会抛出异常,若此处异常,则下面的语句将不会被执行 print ('after')except:# 如果没有异常,则此处将不会被执行,此处相当于异常已经被处理掉了 print ('NOT FOUND File')

结果如下

2 产生异常1 产生方式

1 raise 语句显式抛出异常
2 python解释器自己检测到异常并引发他

1 python自发异常

#!/usr/local/bin/python3.6#coding:utf-8def div(x,y): return x/y # 此处也叫除零异常try: div(1,0) # 此种异常成为运行时异常except: # 此处不写,默认匹配所有异常 print ('Error')

结果如下

#!/usr/local/bin/python3.6#coding:utf-8def div(x,y): return x/y # 此处也叫除零异常try: div(1,0) # 此种异常成为运行时异常except: print ('Error')

结果如下

程序会在异常抛出的地方中断。如果不捕获,就会提前结束程序

2 raise 程序异常

raise 后面什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛类型异常,少用

#!/usr/local/bin/python3.6#coding:utf-8try: 1/0 #产生异常except: try: raise # 此处可捕获的最近被激活的异常 except Exception as e: print (e)

结果如下:

无参实例化

#!/usr/local/bin/python3.6#coding:utf-8try: 1/0 #产生异常except: try: raise Exception #此处是无参实例化异常抛出,此处会将上述异常覆盖,此下将不会有情况,此处抛出的是一个实例 except Exception as e: print (e.__class__.mro()) # 此处__class__表示是获取其实例对应的类,并通过mro进行调用处理

此处是进行有参实例化后的结果

#!/usr/local/bin/python3.6#coding:utf-8try: 1/0 #产生异常except: try: raise Exception('My BDA') # 此处可捕获的最近被激活的异常,此处可对异常进行相关的处理后进行抛出 except Exception as e: print (e)

结果如下:

3 异常匹配捕获1 异常类及相关层次

2 各种异常含义



BaseException 是所有异常的祖先类,及就是所有异常的基类

3 SystemExit 异常

#!/usr/local/bin/python3.6#coding:utf-8import systry: sys.exit() # 此处调用的是系统退出的指令except SystemExit: # 此处匹配SystemExit 系统退出命令 print ('exit')

结果如下

匹配其他非SystemExit父类的异常类

#!/usr/local/bin/python3.6#coding:utf-8import systry: sys.exit() # 此处调用的是系统退出的指令except FileNotFoundError: # 此处匹配SystemExit 系统退出命令,若匹配其他则不会被捕获 print ('exit')print ('outer') # 此处因为退出,因此此处不会被执行

4 KeyboardInterrupt 异常,外界键盘输出的异常 ,对应的是Ctrl+C,需要在系统上执行,在pycharm中Ctrl+c 是复制

如下

#!/usr/local/bin/python3.6#coding:utf-8import systry: import time while True: time.sleep(3) # 此处是一个死循环,可通过外界CTRL+C 进行终止,则打印如下信息 pass except KeyboardInterrupt: print ('ctl + c')print ('outer')

结果如下

5 Exception 及其子类

Exception 是所有内建的,非系统退出的异常的基类,自定义类应该集成自它。

SyntaxError 语法错误,python将其归类到异常下的Exception中,但其不能被捕获。

ArithmeticError 所有算术计算引发的异常,其子类有除零异常情况等

LookupError 使用映射的键或序列的索引无效时引发的异常基类:IndexError,KeyError 等

自定义异常

#!/usr/local/bin/python3.6#coding:utf-8class MyException(Exception): # 自定义类,继承至内部的基类 passtry: raise MyException() # 实例化调用并抛出异常except MyException: print (MyException.mro()) # 打印其祖先类列表

结果如下

6 未实现和未实现异常

NotImplemented 和 NotImplementedError
NotImplemented: 是一个值,相当于是一个None
NotImplementedError: 这是一个类,是一个异常,是抛出异常的时候使用的。

如下:

#!/usr/bin/poython3.6#conding:utf-8# this is testprint (type(NotImplemented))print (type(NotImplementedError))class A: def show(self): raise NotImplementedErrorA().show()

7 同时捕获多个异常

#!/usr/local/bin/python3.6#coding:utf-8class MyException(Exception): # 自定义类,继承至内部的基类 passtry: 1/0 #此处异常后下面的语句将不会被执行 open('test100') raise MyException() # 实例化调用并抛出异常except MyException: #其匹配方式是从上向下进行匹配,若匹配到,则直接返回结果,下面的将不会被再次匹配 print (MyException.mro()) # 打印其祖先类列表except ArithmeticError: print ('除零错误')except FileNotFoundError: print ('文件不存在')except: print ('其他异常')

结果如下

#!/usr/local/bin/python3.6#coding:utf-8class MyException(Exception): # 自定义类,继承至内部的基类 passtry: # 1/0 #此处异常后下面的语句将不会被执行 open('test100') #此处匹配文件异常 raise MyException() # 实例化调用并抛出异常except MyException: #其匹配方式是从上向下进行匹配,若匹配到,则直接返回结果,下面的将不会被再次匹配 print (MyException.mro()) # 打印其祖先类列表except ArithmeticError: print ('除零错误')except FileNotFoundError: print ('文件不存在')except: print ('其他异常')

结果如下

#!/usr/local/bin/python3.6#coding:utf-8class MyException(Exception): # 自定义类,继承至内部的基类 passtry: # 1/0 #此处异常后下面的语句将不会被执行 # open('test100') #此处匹配文件异常 raise MyException() # 实例化调用并抛出异常except MyException: #其匹配方式是从上向下进行匹配,若匹配到,则直接返回结果,下面的将不会被再次匹配 print ('自定义异常') # 打印其祖先类列表except ArithmeticError: print ('除零错误')except FileNotFoundError: print ('文件不存在')except: print ('其他异常')

捕获规则

捕获是从上到下依次比较,如果匹配,则执行匹配的except语句,
如果被一个except语句捕获,则其他的except语句不会再次被执行了
如果没有任何一个except语句捕获到这个异常,则该异常向外抛出

异常不能被捕获的情况

#!/usr/local/bin/python3.6#coding:utf-8try: 1/0 #此处异常后下面的语句将不会被执行except FileNotFoundError: print ('文件不存在')

8 AS 字句

被抛出的异常,应该是异常的实例,可通过as字句进行获取

#!/usr/local/bin/python3.6#coding:utf-8try: 1/0 #此处异常后下面的语句将不会被执行except ArithmeticError as e: # 进行异常的捕获并获取 print (e,type(e))

#!/usr/local/bin/python3.6#coding:utf-8class MyException(Exception): # 自定义异常类 passtry: raise MyException # 抛出类实例,此处是一个空的实例except MyException as e: print (e,type(e)) # 获取类,此处无法获取实例的内容,因为上述没有定义,此处只能获取到其类型

结果如下

添加信息如下

#!/usr/local/bin/python3.6#coding:utf-8class MyException(Exception): # 自定义异常类 passtry: raise MyException('My Exception') # 抛出类实例,此处是一个空的实例except MyException as e: print (e,type(e)) # 获取类,此处无法获取实例的内容,因为上述没有定义,此处只能获取到其类型

结果如下

可定义时间等信息加入其中

#!/usr/local/bin/python3.6#coding:utf-8import datetimeclass MyException(Exception): # 自定义异常类 passtry: raise MyException('My Exception') # 抛出类实例,此处是一个空的实例except MyException as e: print (e,type(e),datetime.datetime.now()) # 获取类,此处无法获取实例的内容,因为上述没有定义,此处只能获取到其类型

4 finally

是必须被执行的语句

#!/usr/local/bin/python3.6#coding:utf-8import datetimeclass MyException(Exception): def __init__(self,xdata=10): self.xdata=xdatatry: raise MyException # 本身自己出错,被底层服务捕获,构造时出现的异常,因此类型异常时从此出现的except ArithmeticError as e: print (e,type(e),e.__class__,datetime.datetime.now().timestamp())except OSError : print ('操作系统异常')finally: #此处是否抛出异常,此代码都会被执行 print ('fin')

结果如下

发现在连接中出现的问题,可以在finally中进行处理,其处理的是最终的清理工作,资源的释放工作,和上下文是一样的

#!/usr/local/bin/python3.6#coding:utf-8try: f = open('test.txt')except FileNotFoundError as e: print ('{} {} {}'.format(e.__class__,e.errno,e.strerror))finally: print ('清理工作') f.close() # 上述的文件不存在,因此其f不存在,因此会报NameError的错误

修改方式如下 ,finally中添加异常处理

#!/usr/local/bin/python3.6#coding:utf-8try: f = open('test.txt')except FileNotFoundError as e: print ('{} {} {}'.format(e.__class__,e.errno,e.strerror))finally: print ('清理工作') try: f.close() # 上述的文件不存在,因此其f不存在,因此会报NameError的错误 except NameError as e: print (e)

#!/usr/local/bin/python3.6#coding:utf-8f=Nonetry: f = open('test.txt')except FileNotFoundError as e: print ('{} {} {}'.format(e.__class__,e.errno,e.strerror))finally: print ('清理工作') if f is not None: f.close()

#!/usr/local/bin/python3.6#coding:utf-8try: f = None # 此处定义f,此处定义和全局定义相同,但一般不建议这样操作 f = open('test.txt')except FileNotFoundError as e: print ('{} {} {}'.format(e.__class__,e.errno,e.strerror))finally: print ('清理工作') if f is not None: f.close()

结果如下

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: return 1 #此处的退出不会影响下面finally的执行 except: pass finally: print ('fin')print (a1())

结果如下

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: 1/0 #此处异常后,下面的return将不会被执行,默认返回为None return "1" #此处的退出不会影响下面finally的执行 except: # 此处表示所有异常都捕获 pass finally: print ('fin')print ("result={}".format(a1())) # 此处抓取返回值

结果如下

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: 1/0 #此处异常后,下面的return将不会被执行,默认返回为None return "1" #此处的退出不会影响下面finally的执行 except: # 此处表示所有异常都捕获 print ('Error') finally: return 100 # 此处定义return,将会覆盖上面的return,且此return下面的语句将不会被执行print ("result={}".format(a1())) # 此处抓取返回值

结果如下

5 异常传递

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: 1/0 # 此处的异常未被处理 finally: print ('a1')def a2(): try: a1() # 此处调用同上面,返回异常 finally: print ('a2')a2() # 此处调用函数,返回异常,异常是逐渐向外扩张的

结果如下

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: 1/0 # 此处的异常未被处理 finally: print ('a1')def a2(): try: a1() # 此处调用同上面,返回异常 except ArithmeticError as e: #在此处处理a1的异常 print ('a2',e) finally: print ('a2')try: a2() # 此处调用函数,返回异常,异常是逐渐向外扩张的except ArithmeticError as e: #因为a2处已经处理了异常,此处不需要再次处理相关异常 print ('out',e)

结果如下

继续抛出异常

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: 1/0 # 此处的异常未被处理 finally: print ('a1')def a2(): try: a1() # 此处调用同上面,返回异常 except ArithmeticError as e: #在此处处理a1的异常 print ('a2',e) raise e #此处持续抛出异常,使得后面继续执行 finally: print ('a2')try: a2() # 此处调用函数,返回异常,异常是逐渐向外扩张的except ArithmeticError as e: #因为a2处已经处理了异常,此处不需要再次处理相关异常 print ('out',e)

结果如下

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: 1/0 # 此处的异常未被处理 finally: print ('a1')def a2(): try: a1() # 此处调用同上面,返回异常 finally: print ('a2') open('aaaaaaaa') # 此处出现异常,则外边会忽略上面的异常,而执行此异常try: a2() # 此处调用函数,返回异常,异常是逐渐向外扩张的except ArithmeticError as e: #因为a2处已经处理了异常,此处不需要再次处理相关异常 print ('out',e)except FileNotFoundError as e: print ('file',e)

结果如下

finally 无法处理异常,其执行进行相关的清理工作
Finally 中出现异常若不管,则外层需要有异常处理和捕获机制

线程级别的问题

#!/usr/local/bin/python3.6#coding:utf-8import threadingimport timedef foo1(): try: 1/0 finally: print ('foo1 fin')def foo2(): time.sleep(4) try: foo1() # finally: print ('foo2 fin') open('acdvsacdsad') while True: # 上面的foo1() 不跑出异常,则此处的while True会一直执行,此处执行,则线程会一直执行,此处下面的会一直检测,检测状态 #为存活状态 time.sleep(1)t=threading.Thread(target=foo2) # 创建线程对象,此处的foo2 会产生异常,t的线程是否会影响死线程t.start()while True: # 当前线程是死循环 time.sleep(1) print ('-------------------------') if t.is_alive(): print ('alive') else: print ('dead')

结果如下

抛出异常后会一直向上,直到线程处,若线程不管,则只会挂掉当前线程,不会影响主线程

主线程操作

#!/usr/local/bin/python3.6#coding:utf-8import threadingimport timedef foo1(): try: 1/0 finally: print ('foo1 fin')def foo2(): time.sleep(4) try: foo1() # finally: print ('foo2 fin') open('acdvsacdsad') while True: # 上面的foo1() 不跑出异常,则此处的while True会一直执行,此处执行,则线程会一直执行,此处下面的会一直检测,检测状态 #为存活状态 time.sleep(1)while True: # 当前线程是死循环 time.sleep(1) print ('-------------------------') foo2()

结果如下

结论

当前线程如果是主线程,则会导致进程直接退出


总结

内部捕获不到异常,会向外层传递异常
但是如果内层有finally且其中有return,break语句,则异常就不会继续向外抛出

异常捕获时机
1 立即捕获,不要将异常向外处理,需要立即返回一个明确的结果

#!/usr/local/bin/python3.6#coding:utf-8def a1(): try: f=open('100') except FileNotFoundError as e: print (e) return 1 # 若匹配此处则返回此值 except FileExistsError as e: print (e) return 2 finally: print ('aaaa')a1()

结果

#!/usr/local/bin/python3.6#coding:utf-8def getaint(data): # 数字的转换 try: res=int(data) except Exception: #此处若有异常,则直接返回为0,此处是立即捕获,立即处理 res=0 return res

2 边界捕获

封装产生了边界
如: 写了一个模块,用户调用这个模块的时候捕获异常,模块内部不需要捕获,处理异常,一旦内部处理了,外部调用者就无法感知了
例如 open 函数,出现的异常交给调用者处理,文件存在了,就不需要创建了,看是否修改还是删除
一般的,自己写了一个类,使用了open函数,但是出现了异常不知道如何处理,就继续向外抛出,一般说最外层也是边界,必须处理这个异常,否则线程将会退出
一般的,给外部提供某些功能的函数是不建议在内部进行处理操作的
业务的分界,模块的外部

6 else

try: 1/0except Exception: print ('except')except: passelse: # 此处针对没有异常时执行的动作 print ('else')finally: print ('fin')

结果如下

没有任何异常发生时,执行

三 总结:1 语句结构

try: <语句> #运行的代码except <异常类>: <语句> # 捕获某种异常的类型except <异常类> as <变量名>: <语句> # 捕获某种类型的异常并获取对象else: <语句> #如果没有发生异常2 概念总结

1 如果try 中语句执行时发生异常,搜索except字句,并执行第一个匹配该异常的except字句
2 如果try中语句执行时发生异常,却没有匹配的except字句,异常将被递交到外层try,如果外层不处理这个异常,异常将继续向外层传递,如果都补处理该异常,则会传递到最外层,如果没有处理,就终止异常所在的线程
3 如果try执行时没有异常,则执行else字句中的语句
4 无论try中是否发生异常,finally字句最终都会被执行