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

问题:如何在Python中正确获取异常消息

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

我注意到在某些情况下,您可以通过如下message字段获取它:

try:
  pass
except Exception as ex:
  print(ex.message)

但在某些情况下(例如在套接字错误的情况下),您必须执行以下操作:

try:
  pass
except socket.error as ex:
  print(ex)

我想知道是否有标准方法可以涵盖大多数情况?

What is the best way to get exceptions’ messages from components of standard library in Python?

I noticed that in some cases you can get it via message field like this:

try:
  pass
except Exception as ex:
  print(ex.message)

but in some cases (for example, in case of socket errors) you have to do something like this:

try:
  pass
except socket.error as ex:
  print(ex)

I wondered is there any standard way to cover most of these situations?


回答 0

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

值得注意的是,EnvironmentError(与子类IOErrorOSError)具有的第一自变量errno,第二的strerror。没有messagestrerror大致类似于通常的message

更一般而言,的子类Exception可以执行他们想要的任何操作。它们可能具有也可能没有message属性。将来的内置Exception可能没有message属性。Exception从第三方库或用户代码导入的任何子类都可能没有message属性。

我认为处理此问题的正确方法是,确定Exception要捕获的特定子类,然后仅捕获那些子类,而不是所有带有的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)

If you look at the documentation for the built-in errors, you’ll see that most Exception classes assign their first argument as a message attribute. Not all of them do though.

Notably,EnvironmentError (with subclasses IOError and OSError) has a first argument of errno, second of strerror. There is no messagestrerror is roughly analogous to what would normally be a message.

More generally, subclasses of Exception can do whatever they want. They may or may not have a message attribute. Future built-in Exceptions may not have a message attribute. Any Exception subclass imported from third-party libraries or user code may not have a message attribute.

I think the proper way of handling this is to identify the specific Exception subclasses you want to catch, and then catch only those instead of everything with an except Exception, then utilize whatever attributes that specific subclass defines however you want.

If you must print something, I think that printing the caught Exception itself is most likely to do what you want, whether it has a message attribute or not.

You could also check for the message attribute if you wanted, like this, but I wouldn’t really suggest it as it just seems messy:

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)

回答 1

为了改善@artofwarfare提供的答案,这是我考虑的一种更整洁的方法来检查message属性并打印它或将Exception对象打印为后备。

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

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


更新#1:

@MadPhysicist发表评论之后,这证明了为什么repr可能需要调用。尝试在解释器中运行以下代码:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

更新#2:

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

To improve on the answer provided by @artofwarfare, here is what I consider a neater way to check for the message attribute and print it or print the Exception object as a fallback.

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

The call to repr is optional, but I find it necessary in some use cases.


Update #1:

Following the comment by @MadPhysicist, here’s a proof of why the call to repr might be necessary. Try running the following code in your interpreter:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

Update #2:

Here is a demo with specifics for Python 2.7 and 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533


回答 2

我有同样的问题。我认为最好的解决方案是使用log.exception,它将自动打印出堆栈跟踪和错误消息,例如:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

I had the same problem. I think the best solution is to use log.exception, which will automatically print out stack trace and error message, such as:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

回答 3

我也有同样的问题。对此进行深入研究,我发现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

I too had the same problem. Digging into this I found that the Exception class has an args attribute, which captures the arguments that were used to create the exception. If you narrow the exceptions that except will catch to a subset, you should be able to determine how they were constructed, and thus which argument contains the message.

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