如何获取发生python异常的实际行号?

时间:2016-10-06 19:03:38

标签: python django exception-handling

我的文件decorators.py

中有以下python装饰器
def catch_exceptions(function):                                           #Line #1
    @wraps(function)                                                      #Line #2
    def decorator(*args, **kwargs):                                       #Line #3
        try:                                                              #Line #4
            return function(*args, **kwargs)                              #Line #5
        except Exception as e:                                            #Line #6
            exc_type, exc_obj, exc_tb = sys.exc_info()                    #Line #7
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]  #Line #8
            print "E=%s, F=%s, L=%s" % (str(e), fname, exc_tb.tb_lineno)  #Line #9
    return decorator                                                      #Line #10

在另一个文件my_file.py中,我使用catch_exceptions装饰器,如下所示:

from decorators import catch_exceptions                                   #Line #1
@catch_exceptions                                                         #Line #2
def my_method()                                                           #Line #3
    print (10/0 - 5/0)                                                    #Line #4

当我运行它时,我得到以下输出:

E=integer division or modulo by zero, F=decorators.py, L=5

而不是将异常位置报告为decorators.py,第5行,我如何才能报告实际文件和最初发生异常的行号?这将是my_file.py中的第4行。

3 个答案:

答案 0 :(得分:3)

您可能需要查看traceback模块

import traceback

try:
    function_that_raises_exception()
except Exception:
    traceback.print_exc()

它将打印整个堆栈跟踪。

答案 1 :(得分:3)

如果你想按照你所描述的那样去做

from functools import wraps
import sys, os, traceback

def catch_exceptions(function):                                           
    @wraps(function)                                                     
    def decorator(*args, **kwargs):                                      
        try:                                                              
            return function(*args, **kwargs)                              
        except Exception as e:                                            
            exc_type, exc_obj, exc_tb = sys.exc_info()
            print "E=%s, F=%s, L=%s" % (str(e), traceback.extract_tb(exc_tb)[-1][0], traceback.extract_tb(exc_tb)[-1][1]) ) 
    return decorator

但你需要知道它仍然是traceback

我认为正在印刷的filename也是一个错误。

所以exc_tb是实际的traceback对象。提取它的数据是由extract_tb()完成的

  

返回从追溯对象tb中提取的最多限制“预处理”堆栈跟踪条目的列表。它对堆栈跟踪的替代格式化很有用。如果省略limit或None,则提取所有条目。 “预处理”堆栈跟踪条目是一个4元组(文件名,行号,函数名*,文本),表示通常为堆栈跟踪打印的信息。

所以traceback.extract_tb(exc_tb)的第二个元素将是装饰器中引发的异常,最后一个元素将出现在你的函数中。所以最后一个索引(-1)就是我们所需要的。然后traceback.extract_tb(exc_tb)[-1][0]将是(我猜)你想要的文件的文件名,而不是 decorators.py ,而traceback.extract_tb(exc_tb)[-1][1]将是触发异常时的行。

答案 2 :(得分:0)

我们可以通过分割traceback.format_exc()的字符串状态来获取行号。请查看我对以下问题的回答,我已在其中添加了示例代码。

enter link description here