python:我怎么知道发生了什么类型的异常?

Sha*_*ang 200 python exception

我有一个主程序调用的函数:

try:
    someFunction()
except:
    print "exception happened!"
Run Code Online (Sandbox Code Playgroud)

但是在函数执行过程中它会引发异常,因此会跳转到该except部分.

我怎样才能确切地看到发生了什么someFunction()导致异常发生?

Lau*_*low 339

其他答案都指出你不应该抓住一般的例外,但似乎没有人想告诉你为什么,这对于理解何时可以打破"规则"至关重要.是一个解释.基本上,这是你不隐藏:

因此,只要您注意不做这些事情,就可以捕获一般异常.例如,您可以通过其他方式向用户提供有关异常的信息,例如:

  • 将异常作为GUI中的对话框呈现
  • 将工作线程或进程中的异常传输到多线程或多处理应用程序中的控制线程或进程

那么如何捕获泛型异常呢?有几种方法.如果您只想要异常对象,请执行以下操作:

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message
Run Code Online (Sandbox Code Playgroud)

确保 message被带到用户的注意力在一个难以错过的方式!如上所示,如果将消息隐藏在许多其他消息中,则打印它可能是不够的.没有引起用户的注意就等于吞下所有异常,如果有一个印象,你应该在阅读了这个页面上的答案后离开,这就是这不是一件好事.使用raise语句结束except块将通过透明地重新捕获已捕获的异常来解决问题.

上述之间的区别和使用except:不带任何参数的区别是双重的:

  • 裸机except:不会给你检查的异常对象
  • 例外SystemExit,KeyboardInterruptGeneratorExit没有被上面的代码捕获,这通常是你想要的.请参阅异常层次结构.

如果你也想要获得相同的堆栈跟踪,如果你没有捕获异常,你可以像这样(仍然在except子句中):

import traceback
print traceback.format_exc()
Run Code Online (Sandbox Code Playgroud)

如果您使用该logging模块,您可以将异常打印到日志(以及消息),如下所示:

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")
Run Code Online (Sandbox Code Playgroud)

如果你想深入挖掘并检查堆栈,查看变量等,请使用except块内的模块post_mortem函数pdb:

import pdb
pdb.post_mortem()
Run Code Online (Sandbox Code Playgroud)

我发现这最后一种方法在追捕bug时非常宝贵.

  • @RikPoggi:天真的想法.当您需要从其他人的代码中捕获异常并且您不知道将引发什么异常时,有许多合理的情况. (16认同)
  • @Rik我想你可能需要_all_这个.例如,如果您有一个带有GUI和后端的程序,并且您希望将后端的所有异常作为GUI消息呈现,而不是让您的程序退出堆栈跟踪.在这种情况下,您应该捕获_generic_ Exception,为对话框创建回溯文本,也记录异常,如果在调试模式下,请输入post-mortem. (9认同)
  • 我认为,traceback.print_exc() 会做与更复杂的 "".join-thing 相同的事情。 (2认同)
  • @Gurgeh 是的,但我不知道他是否想打印它或将其保存到文件或记录它或用它做其他事情。 (2认同)

Ale*_*lex 48

获取异常对象所属的类的名称:

e.__class__.__name__
Run Code Online (Sandbox Code Playgroud)

并使用print_exc()函数也将打印堆栈跟踪,这是任何错误消息的基本信息.

像这样:

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception, e:
    print 'type is:', e.__class__.__name__
    print_exc()
    # print "exception happened!"
Run Code Online (Sandbox Code Playgroud)

你会得到这样的输出:

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi
Run Code Online (Sandbox Code Playgroud)

在打印和分析之后,代码可以决定不处理异常并只执行raise:

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        raise
    print "handling exception"
Run Code Online (Sandbox Code Playgroud)

输出:

special case of CustomException not interfering
Run Code Online (Sandbox Code Playgroud)

翻译打印异常:

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi
Run Code Online (Sandbox Code Playgroud)

raise原始异常继续向上传播调用堆栈之后.(注意可能的陷阱)如果你引发新的异常,它会篡改新的(更短的)堆栈跟踪.

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        #raise CustomException(e.message)
        raise e
    print "handling exception"
Run Code Online (Sandbox Code Playgroud)

输出:

special case of CustomException not interfering
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    
Run Code Online (Sandbox Code Playgroud)

请注意traceback如何不包含calculate()来自9原始异常原点的行的函数e.


hoc*_*chl 13

你通常不应该抓住所有可能的例外情况,try: ... except因为它过于宽泛.抓住那些因任何原因而发生的事情.如果你真的必须,例如,如果你想在调试时找到更多关于某些问题的信息,你应该这样做

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.
Run Code Online (Sandbox Code Playgroud)

  • 在这里使用"从不"这个词从未如此错误.我使用`try:...除了例外:`围绕很多事情,例如使用网络依赖库,或者数据按摩师可能会发送给她的奇怪的东西.当然我也有适当的伐木.这对于允许程序在输入数据中出现单个错误的情况下继续运行至关重要. (16认同)
  • 曾经尝试捕获使用`smtplib`发送电子邮件时可能引发的所有异常? (3认同)
  • 在某些特殊情况下,可能需要捕获所有异常,但一般而言,您应该只捕获您期望的内容,以免意外隐藏您没有预料到的错误。当然,良好的日志记录也是一个好主意。 (2认同)
  • 捕获所有异常是完全合理的。如果您正在调用第三方库,您可能不知道该库中会引发哪些异常。在这种情况下,唯一的办法是捕获所有异常,例如将它们记录到文件中。 (2认同)

Chr*_*ris 10

这些答案对于调试来说很好,但是对于以编程方式测试异常来说,isinstance(e, SomeException)可以很方便,因为它测试了SomeException太的子类,因此您可以创建适用于异常层次结构的功能。


Rik*_*ggi 9

除非somefunction是一个非常糟糕的编码遗留函数,否则你不应该需要你所要求的.

使用multiple except子句以不同的方式处理不同的异常:

try:
    someFunction()
except ValueError:
    # do something
except ZeroDivision:
    # do something else
Run Code Online (Sandbox Code Playgroud)

重点是你不应该捕获泛型异常,而只捕获你需要的异常.我确定你不想影响意外的错误或错误.

  • 如果您使用的是第三方库,则可能不知道其中会引发哪些异常.你怎么可能单独捕获所有这些? (8认同)

Pio*_*ost 7

大多数答案都指向except (…) as (…):语法(这是正确的)但同时没有人想谈论大象在其中sys.exc_info()起作用的房间里的大象.从文档SYS模块(重点煤矿):

此函数返回三个值的元组,这些值提供有关当前正在处理的异常的信息.
(...)
如果堆栈中的任何地方都没有处理异常,则返回包含三个None值的元组.否则,返回的值是(type,value,traceback).它们的含义是:type获取正在处理的异常的类型(BaseException的子类); value获取异常实例(异常类型的实例); traceback获取一个回溯对象(请参阅参考手册),该对象将调用堆栈封装在最初发生异常的位置.

我认为这sys.exc_info()可以被视为对原始问题的最直接的答案:我怎么知道发生了什么类型的异常?

  • 这对我来说是正确的答案,因为它确实解决了发生什么异常的问题,所以我应该用什么来代替裸露的“除了”。只是为了完整起见, `exctype, value = sys.exc_info()[:2]` 将告诉您可以在 ` except` 上使用的异常类型。 (2认同)

wp-*_*com 5

尝试:someFunction()除了Exception,exc:

#this is how you get the type
excType = exc.__class__.__name__

#here we are printing out information about the Exception
print 'exception type', excType
print 'exception msg', str(exc)

#It's easy to reraise an exception with more information added to it
msg = 'there was a problem with someFunction'
raise Exception(msg + 'because of %s: %s' % (excType, exc))
Run Code Online (Sandbox Code Playgroud)