【问题标题】:Get only last traceback without using raise from None?在不使用从无中提高的情况下仅获取最后一次回溯?
【发布时间】:2017-07-15 18:42:34
【问题描述】:

我的项目中有一个常见的情况,我使用自定义异常来包装内置的异常场景,例如:

# meaningless here but in other situations its useful...
try:
   5/0
except ZeroDivisionError as e:
   raise MyCustomException(msg=str(e))

还有一个如下所示的通用异常处理程序:

@app.errorhandler(Exception)   # this decorator is flask related - ignore it
def handle_error(error):
    if isinstance(error, MyCustomException):
        # some code
        # I only want MyCustomException traceback
    else:
        # some other code    
        exc_stack = traceback.format_exc(limit=5)

这里的已知问题是我得到了两个异常回溯,而在 if-case 中我只想要最后一个。

据我所知,这个问题有两种解决方案。

第一个解决方法(使用from None):

try:
   5/0
except ZeroDivisionError as e:
   raise MyCustomException(msg=str(e)) from None   # python3

第二种解决方法(在引发第二个异常之前调用回溯)

try:
    5/0
except ZeroDivisionError as e:
   tracb = traceback.format_exc(limit=5)
   raise MyCustomException(msg=str(e), tracb_msg=tracb)

无需在异常处理程序中调用traceback.format_exc(),只需使用传递给实例的tracb_msg。显然第一个解决方法更简单。

我的问题:

这两种方法都会在代码中重新出现(重复代码/技巧)数十次,每次我都会提出MyCustomException。有没有人想出一个技巧来在处理函数中处理这个一次?

【问题讨论】:

    标签: python python-3.x exception-handling traceback


    【解决方案1】:

    使用__suppress_context__ 属性禁用上下文打印。

    根据docs,使用raise MyCustomException(foo) from bar 将__cause__ 设置为bar,并将__context__ 设置为原始异常(隐式链接异常)。

    仅当 __cause__ 为 None 且 __suppress_context__ 为 false 时,才会显示 __context__ 中的隐式链接异常。

    这是一个例子:

    # Declare an exception that never shows context.
    
    
    class MyCustomException(Exception):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.__suppress_context__ = True
    
    try:
        1/0
    except ZeroDivisionError as e:
        raise MyCustomException(str(e))
    

    这是我得到的输出:

    Traceback (most recent call last):
      File "/home/don/workspace/scratch/scratch.py", line 12, in <module>
        raise MyCustomException(str(e))
    MyCustomException: division by zero
    

    如果我将__suppress_context__ 设置为False,这是输出:

    Traceback (most recent call last):
      File "/home/don/workspace/scratch/scratch.py", line 10, in <module>
        1/0
    ZeroDivisionError: division by zero
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/home/don/workspace/scratch/scratch.py", line 12, in <module>
        raise MyCustomException(str(e))
    MyCustomException: division by zero
    

    【讨论】:

    • 你能解释一下这一行吗:d = list(reversed(sorted(dir(e))))。实际上可能根本没有使用 d,但我想知道我们是否可以以某种方式使用它
    • 对不起,@chefarov,这只是我用来了解异常可用属性的调试语句。我不小心把它丢了。
    • 看起来使用实例属性比使用类属性更好,@chefarov。默认错误处理程序的堆栈跟踪似乎忽略了类属性。我换了我的例子。
    猜你喜欢
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2022-07-07
    • 1970-01-01
    • 2022-08-06
    • 2022-12-20
    • 1970-01-01
    相关资源
    最近更新 更多