Python异常处理的哲学(3)

class ZeroDivZeroError(ZeroDivisionError):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self)
    def __repr__(self):
        return self.value

try:
    # do something and find 0 / 0
    raise ZeroDivZeroError('hahajun')
except ZeroDivZeroError as err:
    print 'except info %s' % err

自定义异常应该直接继承自Exception类或其子类,而不要继承自BaseException.

3. Stack Trace

python执行过程中发生异常,会告诉我们到底哪里出现问题和什么问题。这两种类型的错误信息分别为stack trace和 exception,在程序中分别用traceback object和异常对象表示。

Traceback (most recent call last): File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 270, in <module> 1 / 0 ZeroDivisionError: integer division or modulo by zero

上面的错误信息包含错误发生时当前的堆栈信息(stack trace, 前三行)和异常信息(exception,最后一行),分别存放在traceback objects和抛出的异常对象中。

异常对象及异常信息前面已经介绍过,接下来我们在看一下异常发生时,stack trace的处理。

Traceback objects represent a stack trace of an exception. A traceback object is created when an exception occurs.

这时有两种情况:

异常被try...except捕获

没有被捕获或者干脆没有处理

正常的代码执行过程,可以使用traceback.print_stack()输出当前调用过程的堆栈信息。

3.1 捕获异常

对于第一种情况可以使用下面两种方式获取stack trace信息:

trace_str = traceback.format_exc()

或者从sys.exc_info()中获取捕获的异常对象等的信息,然后格式化成trace信息。

def get_trace_str(self):
    """
    从当前栈帧或者之前的栈帧中获取被except捕获的异常信息;
    没有被try except捕获的异常会直接传递给sys.excepthook
    """
    t, v, tb = sys.exc_info()
    trace_info_list = traceback.format_exception(t, v, tb)
    trace_str = ' '.join(trace_info_list)

至于抛出的包含异常信息的异常对象则可以在try...except结构中的except Exception class as e中获取。 

3.2 未捕获异常

第二种情况,如果异常没有被处理或者未被捕获则会在程序推出前调用sys.excepthook将traceback和异常信息输出到sys.stderr。

def except_hook_func(tp, val, tb): trace_info_list = traceback.format_exception(tp, val, tb) trace_str = ' '.join(trace_info_list) print 'sys.excepthook' print trace_str sys.excepthook = except_hook_func

上面自定义except hook函数来取代sys.excepthook函数。在hook函数中根据异常类型tp、异常值和traceback对象tb获取stack trace。这种情况下不能从sys.exc_info中获取异常信息。

3.3 测试

def except_hook_func(tp, val, tb): trace_info_list = traceback.format_exception(tp, val, tb) trace_str = ' '.join(trace_info_list) print 'sys.excepthook' print trace_str sys.excepthook = except_hook_func try: 1 / 0 except TypeError as e: res = traceback.format_exc() print "try...except" print str(e.message) print res

走的是sys.excepthook处理流程结果:

sys.excepthook Traceback (most recent call last): File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 259, in <module> 1 / 0 ZeroDivisionError: integer division or modulo by zero

将except TypeError as e 改为 except ZeroDivisionError as e,则走的是try...except捕获异常流程,结果如下:

try...except integer division or modulo by zero Traceback (most recent call last): File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 259, in <module> 1 / 0 ZeroDivisionError: integer division or modulo by zero

4. 异常信息收集

讲了这么多,我们看一下如何实现一个程序中trace信息的收集。

class TracebackMgr(object):

def _get_format_trace_str(self, t, v, tb):
        _trace = traceback.format_exception(t, v, tb)
        return ' '.join(_trace)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b572e321e72718341f1cf7c6df4a0e3d.html