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

时间:2012-03-22 14:08:54

标签: python exception

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

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

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

如何确切地看到导致异常发生的someFunction()中发生了什么?

15 个答案:

答案 0 :(得分:297)

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

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

  • 将异常作为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:而不使用任何参数之间的区别是双重的:

  • except:没有为您提供检查的异常对象
  • 上述代码未捕获异常SystemExitKeyboardInterruptGeneratorExit,这通常是您想要的。请参阅exception hierarchy

如果你也想要获得相同的堆栈跟踪,如果你没有捕获异常,你可以这样做(仍然在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()

我发现这最后一种方法在追捕错误时非常宝贵。

答案 1 :(得分:36)

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

e.__class__.__name__

并使用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!"

您将获得如下输出:

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 Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        raise
    print "handling exception"

输出:

special case of CustomException not interfering

解释器打印异常:

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): 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"

输出:

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    

请注意,追踪不包含来自行calculate()的{​​{1}}函数,这是原始异常9的来源。

答案 2 :(得分:13)

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

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

答案 3 :(得分:8)

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

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

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

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

答案 4 :(得分:7)

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

  

此函数返回三个提供信息值的元组   关于当前正在处理的例外情况   (...)
  如果堆栈中的任何地方都没有处理异常,那就是元组   包含三个None值。否则,值   返回的是(类型,值,回溯)。它们的意思是:类型得到了   正在处理的异常的类型(BaseException的子类);   value获取异常实例(异常类型的实例);   traceback获取一个traceback对象(参见参考手册)   将调用堆栈封装在异常点   最初发生的。

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

答案 5 :(得分:5)

尝试:     someFunction() 除了异常,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))

答案 6 :(得分:1)

以下是我处理异常的方法。想法是尝试解决问题,如果这很容易,稍后如果可能的话添加更理想的解决方案。不要在生成异常的代码中解决问题,或者代码会丢失原始算法的跟踪,而原始算法应该写入点。但是,传递解决问题所需的数据,并返回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”文件是否被错误删除。

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

答案 7 :(得分:1)

希望这会有所帮助

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

答案 8 :(得分:0)

为了添加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/

答案 9 :(得分:0)

你可以从Lauritz推荐开始,用:

except Exception as ex:

然后就像print ex一样:

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

对异常类型和异常文本使用以下内容

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

答案 12 :(得分:-1)

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

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

您可以从The Python Tutorial了解有关例外的详情。

答案 13 :(得分:-2)

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

在我看来,您不是在询问如何处理生产代码中的无法预料的异常(假设答案很多),而是如何在开发过程中找出导致特定异常的原因。

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

答案 14 :(得分:-4)

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