【问题标题】:How to get actual line number of where python exception occurred?如何获取发生python异常的实际行号?
【发布时间】:2016-10-06 19:03:37
【问题描述】:

我的文件 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 行。

【问题讨论】:

    标签: python django exception-handling


    【解决方案1】:

    如果你想按照你描述的那样做,那么

    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() 它会做的

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

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

    【讨论】:

    • 是的。这行得通!仅供参考,选择 traceback.extract_tb(exc_tb) 列表中的最后一个元素会更好。它允许此装饰器出现在与方法关联的装饰器堆栈中的任何位置。因此,我已对您的答案进行了编辑。
    • @SaqibAli 是的,这样更好,谢谢,我批准了您的编辑,但是像 lastsecondfirst这样的词> 也需要处理,所以我应用了另一个编辑!很高兴它有帮助!
    【解决方案2】:

    您可能想查看traceback 模块

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

    它将打印整个堆栈跟踪。

    【讨论】:

      【解决方案3】:

      我们可以通过拆分traceback.format_exc()的字符串状态得到行号。请看我对以下问题的回答,我已在此处添加了示例代码。

      enter link description here

      【讨论】:

        猜你喜欢
        • 2018-11-14
        • 2011-03-20
        • 2016-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多