1.基本异常处理方式
多层嵌套try catch只能捕获到异常,无法处理,无法溯源
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s)*2
def main():
try:
bar('0')
except Exception as e:
print('Error:',e)
finally:
print('end')
main()
Error: division by zero
end
2.解释器打印异常
如果未捕获异常,异常就会一直上抛,被解释器捕获并打印错误信息,然后退出程序。
通过解释器打印的错误信息可以看到函数整个调用栈:
- 首先告知第八行main()出错
- 在main()函数中是第六行bar()函数出错
- 在bar()函数中是第四行foo()函数出错
- 在foo中是第二行出错
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s)*2
def main():
bar("0")
main()
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-2-3d66a9ef6914> in <module>
6 bar("0")
7
----> 8 main()
<ipython-input-2-3d66a9ef6914> in main()
4 return foo(s)*2
5 def main():
----> 6 bar("0")
7
8 main()
<ipython-input-2-3d66a9ef6914> in bar(s)
2 return 10 / int(s)
3 def bar(s):
----> 4 return foo(s)*2
5 def main():
6 bar("0")
<ipython-input-2-3d66a9ef6914> in foo(s)
1 def foo(s):
----> 2 return 10 / int(s)
3 def bar(s):
4 return foo(s)*2
5 def main():
ZeroDivisionError: division by zero
3.sys.exc_info和traceback object
Python程序的traceback信息均来源于一个叫做traceback object的对象,而这个traceback object通常是通过函数sys.exc_info()来获取的,先来看一个例子:
import traceback
import sys
def func():
raise SyntaxError("-- func exception --")
def main():
try:
func()
except Exception as e:
exc_type, exc_value, exc_obj = sys.exc_info()
#sys.exc_info()获取了当前处理的exception的三个相关信息:类型,value值,traceback object
#以元组返回
print("exception_type: \t%s,\nexception_value: \t%s,\nexception_object: \t%s,\n" \
%(exc_type,exc_value,exc_obj))
if __name__ == "__main__":
main()
exception_type: <class 'SyntaxError'>,
exception_value: -- func exception --,
exception_object: <traceback object at 0x067507E8>,
4.traceback module
4.1 print_tb
traceback.print_tb(tb[, limit[, file]])
- tb:这个就是traceback object, 是我们通过sys.exc_info获取到的
- limit:这个是限制stack trace层级的,如果不设或者为None,就会打印所有层级的stack trace
- file:这个是设置打印的输出流的,可以为文件,也可以是stdout之类的file-like object。如果不设或为None,则输出到sys.stderr。
import traceback
import sys
def func():
raise Exception("-- func exception --")
def main():
try:
func()
except Exception as e:
exc_type, exc_value, exc_obj = sys.exc_info()
traceback.print_tb(exc_obj)
if __name__ == "__main__":
main()
File "<ipython-input-4-d32102c7a353>", line 9, in main
func()
File "<ipython-input-4-d32102c7a353>", line 5, in func
raise Exception("-- func exception --")
4.2 print_exception
traceback.print_exception(etype, value, tb[, limit[, file]])
- 跟print_tb相比多了两个参数etype和value,分别是exception type和exception value,加上tb(traceback object),正好是sys.exc_info()返回的三个值
- 另外,与print_tb相比,打印信息多了开头的"Traceback (most…)"信息以及最后一行的异常类型和value信息
- 还有一个不同是当异常为SyntaxError时,会有"^"来指示语法错误的位置
import traceback
import sys
def func():
raise Exception("-- func exception --")
def main():
try:
func()
except Exception as e:
exc_type, exc_value, exc_obj = sys.exc_info()
traceback.print_exception(exc_type,exc_value,exc_obj,limit=2,file=sys.stdout)
if __name__ == "__main__":
main()
Traceback (most recent call last):
File "<ipython-input-5-31512e045386>", line 9, in main
func()
File "<ipython-input-5-31512e045386>", line 5, in func
raise Exception("-- func exception --")
Exception: -- func exception --
4.3 print_exc
print_exception()的简化版,自动进行exc_info的操作。
定义:
traceback.print_exc([limit[, file]])
import traceback
import sys
def func():
raise Exception("-- func exception --")
def main():
try:
func()
except Exception as e:
#exc_type, exc_value, exc_obj = sys.exc_info()
traceback.print_exc(limit=2,file=sys.stdout)
if __name__ == "__main__":
main()
Traceback (most recent call last):
File "<ipython-input-6-63e0554ab613>", line 9, in main
func()
File "<ipython-input-6-63e0554ab613>", line 5, in func
raise Exception("-- func exception --")
Exception: -- func exception --
4.4 format_exc
类似于print_exc(limit)
将exc_info 以字符串的形式返回
定义:
traceback.format_exc([limit])
import traceback
import sys
def func():
raise Exception("-- func exception --")
def main():
try:
func()
except Exception as e:
exc_type, exc_value, exc_obj = sys.exc_info()
serror = traceback.format_exc(limit=1)
print(type(serror),"\n",serror)
if __name__ == "__main__":
main()
<class 'str'>
Traceback (most recent call last):
File "<ipython-input-7-4fa75f129078>", line 9, in main
func()
Exception: -- func exception --
5. 错误日志实践
sys.excepthook 为sys模块下的“勾子”函数,可在程序未捕获的异常或者抛出异常时执行此函数,然后停止运行。
sys.excepthook需绑定到一个自建函数上,自建函数的传入参数为**(exc_type,exc_value,exc_object)**
#ErrorLog.py
#traceback 回溯模块可用于确定异常产生的根源位置
import sys, traceback
from datetime import datetime
#新建log文件
fError = open("error.log","a")
#sys.excepthook方法参数为异常类型,异常值,异常对象
def UserErrorHook(tp, val, tb):
#traceback.format_tb方法将异常回溯转为字符串并返回
traceList = traceback.format_tb(tb)
#异常的type value 被写入字符串html
html = repr(tp) + "\n"
html += (repr(val) + "\n")
#回溯信息被写入字符串html
for line in traceList:
html += (line + "\n")
#将异常总体信息输出至标准异常输出,为终端
print(html, file=sys.stderr)
#将时间,异常信息写入fError.log文件
print(datetime.now(),file=fError)
print(html,file=fError)
fError.close()
def main():
sa = input("first:")
sb = input("second:")
try:
ia = int(sa)
ib = int(sb)
fres = ia / ib
except Exception:
print("error and raise:")
raise
else:
print(sa,"/",sb,"=",fres)
#sys.excepthook为一个对象,将一个函数绑定于其可在异常发生(无处理)时接受异常并执行函数
#无绑定即为空,不执行任何
sys.excepthook = UserErrorHook
main()
fError.close() #ErrorLog.py
error and raise:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-130ae0a8ce80> in <module>
48 sys.excepthook = UserErrorHook
49
---> 50 main()
51 fError.close() #ErrorLog.py
<ipython-input-2-130ae0a8ce80> in main()
34
35 try:
---> 36 ia = int(sa)
37 ib = int(sb)
38 fres = ia / ib
ValueError: invalid literal for int() with base 10: ''
总结
- 多层嵌套try catch只能捕获到异常,无法处理,无法溯源
- 如果未捕获异常,异常就会一直上抛,被解释器捕获并打印错误信息,然后退出程序。
- raise作用是不对捕获到的异常进行任何处理,直接抛出。
- sys.exc_info()被用来获取被捕获的异常的相关信息,以元组形式返回。
- traceback.print_tb(tb[, limit[, file]]),向file输出以limit为回溯次数限制的exc_obj
- traceback.print_exception(etype, value, tb[, limit[, file]]),除了输出obj外,还加上了type:value
- traceback.print_exc([limit[, file]]), 前者的简化版,最常用,输出obj+type:value 且集成了sys.exc_info()的功能。
- traceback.format_exc([limit]), 和前者类似,将输出转变为返回相应字符串。
- 结合标准输出可将错误信息记录在log文件中。