python: How do I know what type of exception occurred?
我有一个主程序调用的函数:
1 2 3 4 | try: someFunction() except: print"exception happened!" |
但在函数执行过程中,它会引发异常,因此会跳到
我怎样才能准确地看到导致异常发生的
其他的答案都指出,您不应该捕获一般的异常,但似乎没有人想告诉您原因,这对于理解何时可以打破"规则"至关重要。这是一个解释。基本上,这样你就不会隐藏:
- 发生错误的事实
- 发生错误的详细信息(错误隐藏反模式)
因此,只要您不做这些事情,就可以捕获一般异常。例如,您可以通过另一种方式向用户提供有关异常的信息,例如:
- 在GUI中以对话框形式显示异常
- 将异常从工作线程或进程传输到多线程或多处理应用程序中的控制线程或进程
那么如何捕获一般异常呢?有几种方法。如果您只想要异常对象,请这样做:
1 2 3 4 5 6 7 | try: someFunction() except Exception as ex: template ="An exception of type {0} occurred. Arguments: {1!r}" message = template.format(type(ex).__name__, ex.args) print message |
确保以一种不容错过的方式引起用户的注意。如上图所示,如果消息隐藏在许多其他消息中,那么打印它可能是不够的。不引起用户的注意就等于忽略了所有的例外,如果在阅读完本页上的答案后,你会有一个印象,那就是这不是一件好事。用
上述与仅使用
- 光秃秃的
except: 不会给您异常对象来检查 - 上面的代码并没有捕捉到异常
SystemExit 、KeyboardInterrupt 和GeneratorExit ,这通常是您想要的。请参见异常层次结构。
如果您还希望获得相同的stacktrace,如果不捕获异常,则可以这样获得(仍在except子句中):
1 2 | import traceback print traceback.format_exc() |
如果使用
1 2 3 | import logging log = logging.getLogger() log.exception("Message for you, sir!") |
如果要深入挖掘并检查堆栈、查看变量等,请使用except块内的
1 2 | import pdb pdb.post_mortem() |
我发现这最后一种方法在寻找虫子时非常有用。
获取异常对象所属的类的名称:
1 | e.__class__.__name__ |
使用print_exc()函数还将打印堆栈跟踪,这是任何错误消息的基本信息。
这样地:
1 2 3 4 5 6 7 8 9 10 | 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!" |
您将得到如下输出:
1 2 3 4 5 | type is: CustomException Traceback (most recent call last): File"exc.py", line 7, in <module> raise CustomException("hi") CustomException: hi |
经过打印和分析,代码可以决定不处理异常,只执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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" |
输出:
1 | special case of CustomException not interfering |
解释程序打印异常:
1 2 3 4 5 6 | 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 |
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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" |
输出:
1 2 3 4 5 | 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 |
请注意,回溯不包括来自行
您通常不应该捕获
1 2 3 4 5 | try: ... except Exception as ex: print ex # do whatever you want for debugging. raise # re-raise exception. |
除非
使用多个
1 2 3 4 5 6 | try: someFunction() except ValueError: # do something except ZeroDivision: # do something else |
主要的一点是,您不应该捕获一般的异常,而应该只捕获需要捕获的异常。我敢肯定你不想隐藏意想不到的错误或错误。
大多数答案都指向
This function returns a tuple of three values that give information
about the exception that is currently being handled.
(…)
If no exception is being handled anywhere on the stack, a tuple
containing three None values is returned. Otherwise, the values
returned are (type, value, traceback). Their meaning is: type gets the
type of the exception being handled (a subclass of BaseException);
value gets the exception instance (an instance of the exception type);
traceback gets a traceback object (see the Reference Manual) which
encapsulates the call stack at the point where the exception
originally occurred.
我认为
尝试:一些函数()例外情况除外,不包括:
1 2 3 4 5 6 7 8 9 10 | #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)) |
以下是我处理例外情况的方法。我们的想法是,如果这很容易的话,尝试解决这个问题,如果可能的话,稍后再添加一个更理想的解决方案。不要解决生成异常的代码中的问题,或者代码失去了对原始算法的跟踪,而这些算法应该被写入点中。但是,传递解决该问题所需的数据,并返回lambda,以防在生成该问题的代码之外无法解决该问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
目前,由于我不想对我的应用程序的目的进行无关紧要的思考,所以我没有添加任何复杂的解决方案。但在未来,当我对可能的解决方案了解更多(因为应用程序的设计更多),我可以添加一个由
在所示的示例中,一种解决方案可能是查找存储在其他地方的应用程序数据,例如"app.p"文件是否被错误地删除。
现在,由于编写异常处理程序不是一个明智的想法(我们还不知道解决它的最佳方法,因为应用程序设计将不断发展),我们只需返回简单的修复程序,即像第一次运行应用程序一样(在本例中)。
您可以按照劳瑞兹的建议开始,使用:
1 | except Exception as ex: |
然后像这样对
1 2 3 4 | try: #your try code here except Exception as ex: print ex |
为了添加到Lauritz的答案中,我创建了一个用于异常处理的修饰器/包装器,以及发生哪种类型的异常的包装器日志。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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: {1!r}" message = template.format(type(e).__name__, e.args) logging.exception(message) sys.exit(1) # exit on all exceptions for now return retval |
这可以用decorator在类方法或独立函数上调用:
@通用函数处理程序
完整示例请参见我的博客:http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/
可以通过以下方式捕获实际异常:
1 2 3 4 | try: i = 1/0 except Exception as e: print e |
您可以从Python教程了解更多关于异常的信息。
您的问题是:"我如何才能准确地看到导致异常发生的someFunction()中发生的情况?"
在我看来,您并不是在询问如何处理生产代码中未预见到的异常(正如许多答案所假定的那样),而是如何找出在开发过程中导致特定异常的原因。
最简单的方法是使用一个调试器,它可以在发生未捕获异常的地方停止,最好不要退出,这样您就可以检查变量了。例如,Eclipse开放源代码IDE中的pydev可以做到这一点。要在Eclipse中启用该功能,请打开Debug透视图,在
只需避免捕获异常,python打印的回溯将告诉您发生了什么异常。