【问题标题】:what is the idiomatic way to raise an exception within the exception handler in Python?在 Python 的异常处理程序中引发异常的惯用方法是什么?
【发布时间】:2021-09-17 02:54:07
【问题描述】:

在 Python 中捕获异常并引发另一个异常的正确方法是什么?即,我想捕获类型 1 的异常,操作 Exception 对象并无条件地引发类型 2 的第二个异常,以便调用函数看不到类型 1 的异常,但绝对看到类型 2 的异常,其构造取决于从 type-1 Exception 访问的数据。

这是我试过但不起作用的代码。

            def d(wrt):
                try:
                    return rt.derivative(wrt).canonicalize()
                except CannotComputeDerivative as e:
                    msg = "\n".join([f"When generating derivatives from {self}",
                                     f"  when computing edges of {rt}",
                                     f"  which canonicalizes to {self.canonicalize()}",
                                     f"  computing derivative of {e.rte}",
                                     f"  wrt={e.wrt}",
                                     f"  derivatives() reported: {e.msg}"])
                    raise CannotComputeDerivatives(msg=msg,
                                                   rte=rt,
                                                   wrt=wrt,
                                                   first_types=fts,
                                                   mdtd=wrts)

我认为它不起作用的原因是因为我收到以下消息作为输出:

Error
Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 95, in d
    return rt.derivative(wrt).canonicalize()
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_singleton.py", line 68, in derivative
    return super().derivative(wrt)
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 72, in derivative
    return self.derivative_down(wrt)
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_singleton.py", line 91, in derivative_down
    raise CannotComputeDerivative(
rte.r_rte.CannotComputeDerivative

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/tests/rte_tests.py", line 615, in test_derivatives
    self.assertTrue(rt.derivatives())
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 111, in derivatives
    return trace_graph(self, edges)
  File "/Users/jnewton/Repos/python-rte/pyrte/genus/utils.py", line 199, in trace_graph
    es = edges(v0)  # List[(L,V)]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in edges
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in <listcomp>
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 103, in d
    raise CannotComputeDerivatives(msg=msg,
rte.r_rte.CannotComputeDerivatives

根据MisterMiyagi 的建议,我在raise CannotComputeDerivatives(...) 之后添加了from None。这取得了进展,但似乎unittest 环境并不真正喜欢它。单元测试期间显示的消息如下所示。看起来 unittest 遗憾地截断了消息。

Error
Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/tests/rte_tests.py", line 615, in test_derivatives
    rt.derivatives()
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 111, in derivatives
    return trace_graph(self, edges)
  File "/Users/jnewton/Repos/python-rte/pyrte/genus/utils.py", line 199, in trace_graph
    es = edges(v0)  # List[(L,V)]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in edges
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in <listcomp>
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 103, in d
    raise CannotComputeDerivatives(msg=msg,
rte.r_rte.CannotComputeDerivatives

============== 跟进解决方案: 最初的问题是CannotComputeDerivatives 类的__init__ 函数在没有传递消息字符串的情况下调用super().__init__()。我已经更新了类定义如下。

class CannotComputeDerivatives(Exception):
    def __init__(self, msg, rte, wrt, first_types, mdtd):
        self.msg = msg
        self.rte = rte
        self.wrt = wrt
        self.first_types = first_types
        self.mdtd = mdtd
        super().__init__(msg)

结果是我在单元测试期间收到漂亮的错误消息:

Error
Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/tests/rte_tests.py", line 615, in test_derivatives
    self.assertTrue(rt.derivatives())
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 111, in derivatives
    return trace_graph(self, edges)
  File "/Users/jnewton/Repos/python-rte/pyrte/genus/utils.py", line 199, in trace_graph
    es = edges(v0)  # List[(L,V)]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in edges
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in <listcomp>
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 103, in d
    raise CannotComputeDerivatives(msg=msg,
rte.r_rte.CannotComputeDerivatives: When generating derivatives from Singleton(SOr(odd?, SAtomic(Test2)))
  when computing edges of Singleton(SOr(odd?, SAtomic(Test2)))
  which canonicalizes to Singleton(SOr(odd?, SAtomic(Test2)))
  computing derivative of Singleton(SOr(odd?, SAtomic(Test2)))
  wrt=SOr(SAtomic(Test2), odd?)
  derivatives() reported: Singleton.derivative_down cannot compute derivative of Singleton(SOr(odd?, SAtomic(Test2)))
  wrt=SOr(SAtomic(Test2), odd?)
  disjoint=False
  subtypep=None

【问题讨论】:

  • 这看起来非常准确地描述了您的代码的作用。如果您不希望调用者知道原始异常,请不要在异常处理程序中引发新异常。
  • 你能澄清你在问什么吗? Python 故意链接异常以不隐藏错误细节。您可以raise ... from None 取消之前的异常。
  • @ScottHunter,我不希望调用者知道最初的异常,但我确实希望他知道第二个异常。
  • 然后“......不要在异常处理程序中引发新的”,或者(甚至更好)按照@MisterMiyagi 所说的那样做。
  • @ScottHunter,是的,试试 MisterMiyagi 所说的话。但是关于不引发原始异常的建议并不实用。第一个异常提供了计算第二个异常所需的关键信息,并且是在表达式树的相当深的递归下降中生成的,这可能很大。

标签: python python-3.x exception raise


【解决方案1】:

感谢@MisterMiyagi 建议在raise ... 之后添加from None。这样就避免了系统在异常中报异常的问题。

【讨论】:

    猜你喜欢
    • 2018-09-13
    • 1970-01-01
    • 2014-06-06
    • 2018-03-21
    • 2016-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多