【问题标题】:Modifying exception message without losing stack from raise修改异常消息而不丢失引发的堆栈
【发布时间】:2019-06-03 17:26:07
【问题描述】:

我有一个try/except 子句,它将返回或捕获KeyError,如下所示:

try:
    return super().__new__(globals()[kls])
except KeyError:
    raise

这会在使用不当时生成堆栈跟踪:

>>> g = Grid(cell='Circle')
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    g = Grid(cell='Circle')
  File "<pyshell#1>", line 8, in __new__
    return super().__new__(globals()[kls])
KeyError: 'SHPCircleGrid'
>>> g
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    g
NameError: name 'g' is not defined

这很好,但是我想“扩展/修改”消息以向用户解释如何再次避免此错误;即从:

KeyError: 'SHPCircleGrid'

KeyError: 'SHPCircleGrid'. Use 'Hex', 'Rect' or 'Tri' for cell keyword.

同时为用户维护堆栈。捕获部分中的通用print()g 设置为NoneType,这是我不喜欢的,所以简单地打印不是处理这个问题的方法。添加另一个 raise KeyError('some message') 会打印两个堆栈(“同时处理另一个异常时...”消息),这也是不希望的。

处理此问题的适当方法是什么,以便可以将其扩展到类实例化可能抛出KeyError 的任何其他关键字?

【问题讨论】:

    标签: python python-3.x exception


    【解决方案1】:

    您不能通过将您的消息提供给KeyError 来实现这一点吗:

    try:
        return super().__new__(globals()[kls])
    except KeyError as e:
        key = "'{}'".format(*e.args)
        base = "{}. Use 'Hex', 'Rect' or 'Tri' for cell keyword."
        raise KeyError(base.format(key)) from None
    

    【讨论】:

    • raise KeyError(...) from e 可能比改变原始异常更好
    • @AnthonySottile 这样吗?甚至没有意识到这样做的能力
    • 我试图避免引发多个错误;这会生成两个单独的堆栈。我只是想扩展原始错误的消息。
    • 立即尝试@pstatix
    • 它确实避免了两个堆栈,但我觉得它很多。我可以简单地在方法的开头做一个检查,看看 cell 是否是一个有效的关键字,并引发一个自定义的 KeyError 而不做所有这些。我不明白为什么我不能只是扩展消息。