如何正确地在Python中获取异常消息

Fro*_*art 66 python exception-handling exception

从Python中的标准库组件中获取异常消息的最佳方法是什么?

我注意到在某些情况下你可以通过message字段得到它:

try:
  pass
except Exception as ex:
  print(ex.message)
Run Code Online (Sandbox Code Playgroud)

但在某些情况下(例如,在套接字错误的情况下)你必须做这样的事情:

try:
  pass
except socket.error as ex:
  print(ex)
Run Code Online (Sandbox Code Playgroud)

我想知道是否有任何标准方法可以涵盖大部分情况?

Art*_*are 59

如果您查看内置错误文档,您会看到大多数Exception类将其第一个参数指定为message属性.但并非所有人都这样做.

值得注意的是,EnvironmentError(带子类IOErrorOSError)的第一个参数是errno,第二个strerror.没有message... strerror大致类似于通常的情况message.

更一般地说,子类Exception可以做任何他们想做的事情.它们可能有也可能没有message属性.未来的内置Exceptions可能没有message属性.Exception从第三方库或用户代码导入的任何子类可能没有message属性.

我认为处理这个问题的正确方法是确定Exception你想要捕获的特定子类,然后只使用a捕获那些而不是所有的except Exception子类,然后利用特定子类定义的任何属性.

如果你必须print做某事,我认为打印被抓住Exception本身最有可能做你想要的,无论它是否有message属性.

你也可以检查一下你想要的消息属性,就像这样,但我不会真的建议它,因为它看起来很麻烦:

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)
Run Code Online (Sandbox Code Playgroud)

  • @FrozenHeart - `print()`自动为你调用`str()`.没有理由自己手动调用它,虽然它是无害的,因为在字符串上调用`str()`只会返回字符串本身. (3认同)

ace*_*was 19

为了改进@artofwarfare提供的答案,我认为这是一种更简洁的方法来检查message属性并打印它或打印Exception对象作为后备.

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))
Run Code Online (Sandbox Code Playgroud)

调用repr是可选的,但我发现在某些用例中它是必要的.


更新#1:

根据@MadPhysicist的评论,这里有一个证明为什么repr可能需要调用.尝试在解释器中运行以下代码:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))
Run Code Online (Sandbox Code Playgroud)

更新#2:

这是一个包含Python 2.7和3.5细节的演示:https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533

  • 谢谢!!`repr(e)` 是目前唯一可以帮助我打印在某些特定情况下捕获的错误的至少少量信息的解决方案。`repr(e)` 产生 `KeyError(0,)` (这就是错误),而 `str(e)` 或 `e.message` 分别只产生 `0` 或根本不产生任何结果。 (4认同)
  • 您几乎肯定会想要`str`而不是`repr`。 (2认同)
  • 与 `str` 相比,`repr` 只是添加了类名。我建议使用 print('{e.__class__.__name__}: {e}'.format(e=e))`,而不是使用 `repr`。打印输出更干净,并且与 raise 本身的输出一致。 (2认同)

小智 7

我也有同样的问题。深入研究,我发现 Exception 类有一个args属性,它捕获用于创建异常的参数。如果您将 except 将捕获的异常缩小到一个子集,您应该能够确定它们的构造方式,从而确定哪个参数包含消息。

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling
Run Code Online (Sandbox Code Playgroud)


小智 7

from traceback import format_exc


try:
    fault = 10/0
except ZeroDivision:
    print(format_exc())
Run Code Online (Sandbox Code Playgroud)

另一种可能性是使用回溯模块中的 format_exc() 方法。