我们虽然经常用到try...except 作为异常补货,但是其实很少去研究try源码和机制,也许点进去看过,也是看不出个所以然来
class Exception(BaseException): """ Common base class for all non-exit exceptions. """ def __init__(self, *args, **kwargs): # real signature unknown pass
继承了BaseException
class BaseException(object): """ Common base class for all exceptions """ def with_traceback(self, tb): # real signature unknown; restored from __doc__ """ Exception.with_traceback(tb) -- set self.__traceback__ to tb and return self. """ pass def __delattr__(self, *args, **kwargs): # real signature unknown """ Implement delattr(self, name). """ pass def __getattribute__(self, *args, **kwargs): # real signature unknown """ Return getattr(self, name). """ pass def __init__(self, *args, **kwargs): # real signature unknown pass ..................
是不是仍然一脸懵逼,同感,哈哈,那还是直接上代码,事实大于雄辩
代码举例转自https://blog.csdn.net/u010159842/article/details/54924940 我觉得这个作者写的很清楚
一:在 try 中 raise一个异常,就立刻转入 except 中执行,在except 中遇到 return 时,就强制转到 finally 中执行, 在 finally 中遇到 return 时就返回,最终函数返回值是finally 返回的
ef test1(): try: print('to do stuff') raise Exception('hehe') print('to return in try') return 'try' except Exception: print('process except')return 'except' finally: print('to return in finally') return 'finally' test1Return = test1() print('test1Return : ' + test1Return) #输出: #to do stuff #process except #to return in finally #test1Return : finally
二:这里在 try 中没有抛出异常,因此不会转到 except 中,但是在try 中遇到return时,也会立即强制转到finally中执行,并在finally中返回
def test2(): try: print('to do stuff') print('to return in try') return 'try' except Exception: print('process except') print('to return in except') return 'except' finally: print('to return in finally') return 'finally' test2Return = test2() print('test1Return : ' + test2Return) #输出: #to do stuff #to return in try #to return in finally #test2Return : finally
test1和test2得到的结论:
无论是在try还是在except中,遇到return时,只要设定了finally语句,就会中断当前的return语句,跳转到finally中执行,如果finally中遇到return语句,就直接返回,不再跳转回try/excpet中被中断的return语句
三
def test3(): i = 0 try: i += 1 print('i in try : %s'%i) raise Exception('hehe') except Exception: i += 1 print('i in except : %s'%i) return i finally: i += 1 print ('i in finally : %s'%i ) print('test3Return : %s'% test3()) #输出: #i in try : 1 #i in except : 2 #i in finally : 3 #test3Return : 2
def test4(): i = 0 try: i += 1 return i finally: i += 1 print ('i in finally : %s'%i ) print('test4Return : %s' % test4()) #输出 #i in finally : 2 #test4Return : 1
test3和test4得到的结论:
在except和try中遇到return时,会锁定return的值,然后跳转到finally中,如果finally中没有return语句,则finally执行完毕之后仍返回原return点,将之前锁定的值返回(即finally中的动作不影响返回值),如果finally中有return语句,则执行finally中的return语句。
四:test5得到的结论:在一个循环中,最终要跳出循环之前,会先转到finally执行,执行完毕之后才开始下一轮循环
def test5(): for i in range(5): try: print('do stuff %s'%i) raise Exception(i) except Exception: print('exception %s'%i) continue finally: print('do finally %s'%i) test5() 输出 do stuff 0 exception 0 do finally 0 do stuff 1 exception 1 do finally 1 do stuff 2 exception 2 do finally 2 do stuff 3 exception 3 do finally 3 do stuff 4 exception 4 do finally 4
注:
python的错误也是class,所有的错误类型都继承自BaseException,各个类型的错误之间可能会存在继承关系,比如UnicodeError是ValueError的子类,
如果catch语句中同时出现了这两个错误,且UnicodeError在ValueError的后面处理的,那么永远都捕获不到UnicodeError。
python中内置的常用错误类型继承关系:
使用try…excetp捕获错误一个好处是,可以跨层调用,比如main()调用foo(),foo()调用bar(),而错误是在bar中出现的,最后我们只需要在main()中捕获就行。
五:举个工作中的例子
# 首先下面的代码是一段有问题的代码哦,是对try机制了解不清晰 import time def pushMsg(ss): try: res=10/ss # 设置报错点 if res: return res except Exception as e: return False # 该函数需求是调用pushMsg()函数,默认三次不成功返回,就不再调用 def exceptTest(ss): cnt = 1 while cnt <= 3: try: res = pushMsg(ss) print("res:",res) if res: break # 如果正常返回了,退出循环 except Exception as e: print(e) continue # 本意收集 finally: cnt += 1 time.sleep(1) print("cnt",cnt) if cnt > 3: print("3 times push failed!") return True # 分两种情况(主要考量except和finall,在两层套用情况下执行顺序,也就是内层函数也用了try ,并且return False) # 第一种:程序正常走下来,不设置错误 ss传值非零 ss=1 exceptTest(ss) # 打印执行顺序:只有 res: 10.0,因为内外两层try ,都没有捕获到错误,except和finally 里面都没有执行打印,并且判断res有值就直接break退出循环了 # 第二种情况,置报错 ss传值为零 ss=0 exceptTest(ss) # 打印执行顺序:下面的顺序,先打印了finally里面的内容,再打印了返回值res,但是!为什么except里面的东西没有打印呢! """ cnt 2 res: False cnt 2 res: False cnt 3 res: False cnt 4 3 times push failed! """ # 总结上面两种情况,无论是有无异常,except里面的东西都没有执行,那外层的try根本没有用呀,这是为什么呢! # 经过研究,发现内层函数pushMsg(ss),也用了try ,但是他直接return True或者False ,并没有把内层捕获到的错误传到外层,所以外层的try也就捕获不到异常了,y # 外层函数就会默认没有错误,直接执行finally里面的内容
那么代码就可以这么改
def pushMsg(ss): try: res=10/ss # 设置报错点 if res: return res except Exception as e: import traceback traceback.print_exc() return False def exceptTest(ss): cnt = 1 while cnt <= 3: res = pushMsg(ss) print("res:", res) if res: break else: cnt += 1 time.sleep(1) if cnt > 3: print("3 times push failed!") return True