【问题标题】:Don't show Python raise-line in the exception stack不要在异常堆栈中显示 Python raise-line
【发布时间】:2023-03-19 13:16:02
【问题描述】:

当我在我的 Python 库中引发我自己的异常时,异常堆栈将引发行本身显示为堆栈的最后一项。这显然不是错误,在概念上是正确的,但是当您在外部使用代码(例如作为模块)时,将重点放在对调试无用的东西上。

有没有办法避免这种情况并强制 Python 将上一个到最后一个堆栈项显示为最后一个,就像标准 Python 库一样。

【问题讨论】:

  • 从编译的 C 代码中引发的 raise 行是隐藏的(因为没有要显示的 raise 行)。标准库的 Python 部分仍将在回溯中显示 raise 语句。
  • 也许你可以破解 sys.excepthook 以排除最后一行,如果它是 raise。但一般是不可能的,习惯就好了。
  • 你总是可以提出一个有用的异常。
  • 这太可怕了——当然你希望能够看到异常来自哪里!没有什么说异常最有趣的帧是它生成的正上方,异常的本质是堆栈跟踪的重要部分可能在它的任何地方,从生成它的代码块一直到起来。
  • 对于那些说这是一个糟糕想法的人,我会将上述情况与本机 python 函数引发的异常进行比较。它们将异常显示为来自错误使用函数的行,而不是该函数中引发异常的行。我不认为在这种情况下这是一个坏主意,因为您可以相信错误不是来自函数本身的问题,因为它已经过 python 开发人员的严格测试。为什么不在这里?

标签: python exception stack raise


【解决方案1】:

适当的警告:修改解释器的行为通常是不受欢迎的。在任何情况下,准确查看引发错误的位置可能有助于调试,尤其是当函数可能因多种不同原因引发错误时。

如果您使用traceback 模块,并将sys.excepthook 替换为自定义函数,则可能可以这样做。但是进行更改会影响整个程序的错误显示,而不仅仅是您的模块,因此可能不推荐。

您还可以查看将代码放入 try/except 块中,然后修改错误并重新引发它。但是您最好将时间花在减少意外错误的可能性上,并为可能出现的错误编写信息性错误消息。

【讨论】:

    【解决方案2】:

    我建议不要使用异常机制来验证参数,尽管那样很诱人。将异常作为条件进行编码就像是在说,“作为开发人员,如果我没有想到我提供的参数可能导致的所有不良情况,那么我的应用程序就会崩溃。也许使用异常不仅是您无法控制的,而且是在操作系统或硬件或 Python 语言等其他东西的控制下会更合乎逻辑,我不知道。但在实践中,当您请求解决方案时,我会使用异常。

    为了回答您的问题,在某种程度上,编写代码同样简单:

    class MyObject(object):
        def saveas(self, filename):
            if not validate_filename(filename):
                return False
            ...
    

    调用者

    if not myobject.saveas(filename): report_and_retry()
    

    也许不是一个很好的答案,只是需要考虑一下。

    【讨论】:

    • 我不得不对此表示赞同,因为我要尽可能避免异常,只是告诉我的程序处理它,跳过它,记录问题,然后继续走。我在这里的调试成功比像其他人一样到处抛出异常...基本上我使用的是 print() 而不是 raise
    • 我刚刚也想到了这一点的另一面,这可能是大多数人对此投反对票的原因(我仍然不会,因为我的最后一条评论仍然存在),大多数优秀的开发人员不要只为几乎每个错误的用例抛出异常,只有应该引发异常的特定情况才会得到提升......当然上述情况仍然可能发生在特定情况下,甚至您的代码都无法捕获。 eg: filename 是一个代表 str 的对象。
    【解决方案3】:

    您可以在 python 中创建自己的异常挂钩。下面是我正在使用的代码示例。

    import sys
    import traceback
    
    def exceptionHandler(got_exception_type, got_exception, got_traceback):
        listing  = traceback.format_exception(got_exception_type, got_exception, got_traceback)
        # Removing the listing of statement raise (raise line). 
        del listing[-2]
        filelist = ["org.python.pydev"] # avoiding the debuger modules.
        listing = [ item for item in listing if len([f for f in filelist if f in item]) == 0 ]
        files = [line for line in listing if line.startswith("  File")]
        if len(files) == 1:
            # only one file, remove the header.
            del listing[0]
        print>>sys.stderr, "".join(listing)
    

    下面是我在自定义异常代码中使用的一些行。

    sys.excepthook = exceptionHandler
    raise Exception("My Custom error message.")
    

    在方法异常中,如果您想忽略任何不需要的文件,您可以在“文件名”列表中添加文件名或模块名。因为我在 Eclipse 中使用 pydev 调试器,所以我忽略了 python pydev 模块。

    以上内容在我自己的模块中用于特定目的。您可以修改并将其用于您的模块。

    【讨论】:

      猜你喜欢
      • 2014-01-24
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多