Python异常处理及错误日志

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.解释器打印异常

如果未捕获异常,异常就会一直上抛,被解释器捕获并打印错误信息,然后退出程序。
通过解释器打印的错误信息可以看到函数整个调用栈:

  1. 首先告知第八行main()出错
  2. 在main()函数中是第六行bar()函数出错
  3. 在bar()函数中是第四行foo()函数出错
  4. 在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: ''

总结

  1. 多层嵌套try catch只能捕获到异常,无法处理,无法溯源
  2. 如果未捕获异常,异常就会一直上抛,被解释器捕获并打印错误信息,然后退出程序。
  3. raise作用是不对捕获到的异常进行任何处理,直接抛出。
  4. sys.exc_info()被用来获取被捕获的异常的相关信息,以元组形式返回。
  5. traceback.print_tb(tb[, limit[, file]]),向file输出以limit为回溯次数限制的exc_obj
  6. traceback.print_exception(etype, value, tb[, limit[, file]]),除了输出obj外,还加上了type:value
  7. traceback.print_exc([limit[, file]]), 前者的简化版,最常用,输出obj+type:value 且集成了sys.exc_info()的功能。
  8. traceback.format_exc([limit]), 和前者类似,将输出转变为返回相应字符串。
  9. 结合标准输出可将错误信息记录在log文件中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值