如何确定发生了什么类型的异常?

some_function()在执行时引发一个异常,因此程序跳转到 except:

try:
some_function()
except:
print("exception happened!")

如何查看导致异常发生的原因?

333502 次浏览

你通常不应该用try: ... except捕获所有可能的异常,因为这太宽泛了。只要抓住那些无论出于什么原因都会发生的事情。如果您真的必须这样做,例如,如果您想在调试时了解有关某个问题的更多信息,那么您应该这样做

try:
...
except Exception as ex:
print ex # do whatever you want for debugging.
raise    # re-raise exception.

实际的异常可以通过以下方式捕获:

try:
i = 1/0
except Exception as e:
print e

你可以从Python教程中了解更多关于异常的信息。

其他答案都指出不应该捕获通用异常,但似乎没有人愿意告诉您原因,这对于理解何时可以打破“规则”至关重要。在这里是一个解释。基本上,这样你就不会隐藏:

因此,只要您注意不做这些事情,就可以捕获泛型异常。例如,你可以用另一种方式向用户提供异常信息,比如:

  • 在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

使确定 message以一种难以忽视的方式引起用户的注意!如上所示,如果消息隐藏在许多其他消息中,则打印它可能是不够的。未能引起用户的注意就等于吞下所有异常,如果在阅读本页上的答案后,你应该有一个印象,那就是这是这不是好事。用raise语句结束异常块将通过透明地重新引发被捕获的异常来解决问题。

上述方法与只使用except:而不带任何参数之间的区别是双重的:

  • except:不会给你要检查的异常对象
  • 异常SystemExitKeyboardInterruptGeneratorExit不会被上面的代码捕获,这通常是你想要的。参见异常层次结构

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

import traceback
print traceback.format_exc()

如果你使用logging模块,你可以像这样将异常打印到日志中(以及一条消息):

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

如果你想更深入地研究堆栈,查看变量等,请使用except块内pdb模块的post_mortem函数:

import pdb
pdb.post_mortem()

我发现最后一种方法在查找bug时非常有用。

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

e.__class__.__name__

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

是这样的:

from traceback import print_exc


class CustomException(Exception): pass


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

你会得到这样的输出:

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

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

from traceback import print_exc


class CustomException(Exception): pass


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


try:
calculate()
except CustomException as e:
# here do some extra steps in case of CustomException
print('custom logic doing cleanup and more')
# then re raise same exception
raise

输出:

custom logic doing cleanup and more

和解释器打印异常:

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

raise之后,原始异常继续向上传播调用堆栈。(当心可能的陷阱)如果你引发新的异常,它会携带新的(更短的)堆栈跟踪。

from traceback import print_exc


class CustomException(Exception):
def __init__(self, ok):
self.ok = ok


def calculate():
raise CustomException(False)


try:
calculate()
except CustomException as e:
if not e.ok:
# Always use `raise` to rethrow exception
# following is usually mistake, but here we want to stress this point
raise CustomException(e.ok)
print("handling exception")

输出:

Traceback (most recent call last):
File "test.py", line 13, in <module>
raise CustomException(e.message)
__main__.CustomException: hi

注意traceback如何不包括calculate()函数,该函数来自9行,这是原始异常e的起源。

只要避免捕获异常,Python打印的回溯就会告诉你发生了什么异常。

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

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

try:
someFunction()
except ValueError:
# do something
except ZeroDivision:
# do something else

重点是不应该捕获通用异常,而应该只捕获需要捕获的异常。我相信您不希望看到意外的错误或bug。

在Python 2中,以下代码很有用

except 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))

为了补充Lauritz的答案,我创建了一个用于异常处理的装饰器/包装器,并且包装器记录发生了哪种类型的异常。

class general_function_handler(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
return self.__class__(self.func.__get__(obj, type))
def __call__(self, *args, **kwargs):
try:
retval = self.func(*args, **kwargs)
except Exception, e :
logging.warning('Exception in %s' % self.func)
template = "An exception of type {0} occured. Arguments:\n{1!r}"
message = template.format(type(e).__name__, e.args)
logging.exception(message)
sys.exit(1) # exit on all exceptions for now
return retval

这可以在类方法或带有装饰器的独立函数上调用:

@general_function_handler

关于完整的例子,请参阅我的博客:http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/

你的问题是:“我如何才能确切地看到someFunction()中发生了什么导致异常发生?”

在我看来,您不是在问如何处理生产代码中不可预见的异常(正如许多答案所假设的那样),而是在问如何找出在开发过程中导致特定异常的原因。

最简单的方法是使用调试器,该调试器可以在未捕获异常发生的地方停止,最好不要退出,以便您可以检查变量。例如,Eclipse开源IDE中的PyDev可以做到这一点。要在Eclipse中启用它,打开Debug透视图,在Run菜单中选择Manage Python Exception Breakpoints,并检查Suspend on uncaught exceptions

你可以像Lauritz推荐的那样开始:

except Exception as ex:

然后就像这样print ex:

try:
#your try code here
except Exception as ex:
print ex

下面是我处理异常的方式。我们的想法是,如果容易的话,尝试解决问题,然后在可能的情况下添加一个更理想的解决方案。不要在生成异常的代码中解决问题,否则代码会失去原始算法的跟踪,而原始算法应该被准确地编写。但是,传递解决问题所需的数据,并返回一个lambda,以防在生成它的代码之外无法解决问题。

path = 'app.p'


def load():
if os.path.exists(path):
try:
with open(path, 'rb') as file:
data = file.read()
inst = pickle.load(data)
except Exception as e:
inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
else:
inst = App()
inst.loadWidgets()


# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
class_name = e.__class__.__name__
print(class_name + ': ' + str(e))
print('\t during: ' + during)
return easy

目前,由于我不想考虑应用程序的用途,所以我没有添加任何复杂的解决方案。但在未来,当我知道更多可能的解决方案(因为应用程序设计得更多),我可以添加一个由during索引的解决方案字典。

在这个例子中,一种解决方案可能是寻找存储在其他地方的应用程序数据,比如‘app.p’文件被错误删除了。

现在,因为编写异常处理程序不是一个明智的想法(我们还不知道解决它的最佳方法,因为应用程序的设计将不断发展),我们只是返回简单的修复,这就像我们第一次运行应用程序一样(在这种情况下)。

大多数答案指向except (…) as (…):语法(这是正确的),但同时没有人想谈论房间里的大象,而大象是sys.exc_info()函数。 来自sys模块的文档(强调我的):

这个函数返回一个由三个值组成的元组 关于当前正在处理的异常 (…)< br > 如果堆栈上的任何位置都没有异常被处理,则为元组 返回三个None值。否则,值 返回有(type, value, traceback)。它们的含义是:类型得到 被处理异常的类型 (BaseException的子类); 值获取异常实例(异常类型的实例); traceback获取一个traceback对象(参见参考手册) 在异常所在的位置封装调用堆栈 最初发生。< / p >

我认为sys.exc_info()可以被视为对最初的我如何知道发生了什么类型的异常?问题的最直接的回答

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

使用下面的异常类型和异常文本

import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'")+"-"+(str(sys.exc_info()[1])))

如果你只想要异常类型:使用——>

import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'"))

由于Rajeshwar

希望这对你有帮助

import sys
varExcepHandling, varExcepHandlingZer = 2, 0
try:
print(varExcepHandling/varExcepHandlingZer)
except Exception as ex:
print(sys.exc_info())

'sys.exc_info()'将返回一个元组,如果你只想要异常类名,请使用'sys.exc_info()[0]'

注意:如果你想看到所有的异常类,只需要写dir(__builtin__)

使用type类和as语句

try:#code
except Exception as e:
m=type(e)
#m is the class of the exception
strm=str(m)
#strm is the string of m