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


104

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

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

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

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

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

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


1
您将两个不同的东西混为一谈-except Foo as bar:相同except Foo, bar:(除了前者是较新的东西,并且将继续在3.x中使用),无论错误是随message属性带来的还是独立发生的。
jonrsharpe 2015年

1
@FrozenHeart您是否在问访问.message错误是否是标准方式?
Anand S Kumar

您的第二个示例print(msg)只是print(str(msg))
Salo 2015年

@Anand S Kumar Yep。在任何情况下都可以使用吗?
FrozenHeart 2015年

5
我认为访问message已被弃用。
乔纳森·莱因哈特

Answers:


102

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

值得注意的是,EnvironmentError(与子类IOErrorOSError)具有的第一自变量errno,第二的strerror。没有message...strerror大致类似于通常的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)

感谢你的回答。有什么特别的理由要使用str(ex)而不仅仅是ex
FrozenHeart 2015年

4
@FrozenHeart-print()自动呼叫str()您。没有必要手动手动调用它,尽管它无害,因为调用str()字符串只会返回字符串本身。
ArtOfWarfare 2015年

1
我认为@ArtOfWarfare可能是str()message类型的问题unicode
kratenko

39

为了改善@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


1
getattr如果传入的对象没有请求的属性,则引发异常。如果您想做类似的事情,我认为您应该使用可选的第三个参数getattr,例如:print getattr(e, 'message', e)。比我做的好得多。另一个选择是print(e.message if hasattr(e, 'message') else e)
ArtOfWarfare

2
您几乎肯定会想要str而不是repr
疯狂物理学家

2
与相比strrepr只添加了类名。repr我建议不要使用,而是使用print('{e.__class__.__name__}: {e}'.format(e=e))。打印输出更清洁,并粘附在提升输出本身上。
卡迪

1
基于上述发现,我发现最有用的是'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
shadi 19/12/23

1
谢谢!!repr(e)到目前为止,它是唯一的解决方案,可帮助我在某些特定情况下针对我发现的错误至少打印最少的信息。repr(e)产生KeyError(0,)(这就是错误所在),分别是str(e)e.message只产生0或根本不产生任何结果。
FlorianH

0

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

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

2
什么log啊 我刚import log在Python 2.7.13上尝试过,并收到一条消息,提示没有模块具有该名称。是通过添加的内容pip还是在较新版本的python中添加的内容(我知道,我知道,我需要更新至Python 3 ...我将在CentOS默认情况下停止随Python 2一起发货时这样做)。 ...)
ArtOfWarfare

7
他/她可能正在使用python中的日志记录模块,然后将记录器实例化为日志变量。import logging\ nlog = logging.getLogger(__name__)
Josepas,

0

我也有同样的问题。对此进行深入研究,我发现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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.