How to print the full traceback without halting the program?
我正在编写一个程序,它解析10个网站,定位数据文件,保存文件,然后解析它们以生成可以在numpy库中随时使用的数据。这个文件通过坏链接、格式不好的XML、缺少条目和其他我还没有分类的东西遇到了大量的错误。我最初制作这个程序是为了处理这样的错误:
1 2 3 4 | try: do_stuff() except: pass |
但现在我想记录错误:
1 2 3 4 | try: do_stuff() except Exception, err: print Exception, err |
注意:这是打印到日志文件以供以后查看。这通常会打印非常无用的数据。我想要的是在不进行尝试的情况下打印错误触发时打印的完全相同的行,除了截取异常,但我不希望它停止我的程序,因为它嵌套在一系列的for循环中,我希望看到它完成。
如果这是你想要的,
1 2 3 4 5 6 7 8 9 | import traceback import sys try: do_stuff() except Exception: print(traceback.format_exc()) # or print(sys.exc_info()[0]) |
其他一些答案已经指出了回溯模块。
请注意,使用
1 2 3 4 5 6 7 8 9 10 11 | import traceback try: raise TypeError("Oups!") except Exception, err: try: raise TypeError("Again !?!") except: pass traceback.print_exc() |
…将显示上一个异常的回溯:
1 2 3 4 | Traceback (most recent call last): File"e.py", line 7, in <module> raise TypeError("Again !?!") TypeError: Again !?! |
如果您真的需要访问原始的回溯,一个解决方案是将从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import traceback import sys try: raise TypeError("Oups!") except Exception, err: try: exc_info = sys.exc_info() # do you usefull stuff here # (potentially raising an exception) try: raise TypeError("Again !?!") except: pass # end of useful stuff finally: # Display the *original* exception traceback.print_exception(*exc_info) del exc_info |
生产:
1 2 3 4 | Traceback (most recent call last): File"t.py", line 6, in <module> raise TypeError("Oups!") TypeError: Oups! |
不过,很少有这样的陷阱:
来自
sys_info 号文件:
Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. [...] If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement)
但是,来自同一个文件:
Beginning with Python 2.2, such cycles are automatically reclaimed when garbage collection is enabled and they become unreachable, but it remains more efficient to avoid creating cycles.
另一方面,通过允许您访问与异常关联的回溯,python 3产生了一个不那么令人惊讶的结果:
1 2 3 4 5 6 7 8 9 10 11 | import traceback try: raise TypeError("Oups!") except Exception as err: try: raise TypeError("Again !?!") except: pass traceback.print_tb(err.__traceback__) |
…将显示:
1 2 | File"e3.py", line 4, in <module> raise TypeError("Oups!") |
如果正在调试并且只想查看当前堆栈跟踪,则可以简单地调用:
不需要手动引发异常以再次捕获它。
How to print the full traceback without halting the program?
如果您不想在出现错误时停止程序,则需要尝试/排除以下情况来处理该错误:
1 2 3 4 | try: do_something_that_might_error() except Exception as error: handle_the_error(error) |
为了提取完整的回溯,我们将使用标准库中的
1 | import traceback |
为了创建一个相当复杂的stacktrace来证明我们得到了完整的stacktrace:
1 2 3 4 5 | def raise_error(): raise RuntimeError('something bad happened!') def do_something_that_might_error(): raise_error() |
印刷
要打印完整的回溯,请使用
1 2 3 4 | try: do_something_that_might_error() except Exception as error: traceback.print_exc() |
哪些印刷品:
1 2 3 4 5 | Traceback (most recent call last): File"<stdin>", line 2, in <module> File"<stdin>", line 2, in do_something_that_might_error File"<stdin>", line 2, in raise_error RuntimeError: something bad happened! |
优于打印、日志记录:
然而,最佳实践是为模块设置一个记录器。它将知道模块的名称,并能够更改级别(以及其他属性,如处理程序)。
1 2 3 | import logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) |
在这种情况下,您需要使用
1 2 3 4 | try: do_something_that_might_error() except Exception as error: logger.exception(error) |
哪些日志:
1 2 3 4 5 6 | ERROR:__main__:something bad happened! Traceback (most recent call last): File"<stdin>", line 2, in <module> File"<stdin>", line 2, in do_something_that_might_error File"<stdin>", line 2, in raise_error RuntimeError: something bad happened! |
或者您只需要字符串,在这种情况下,您将需要
1 2 3 4 | try: do_something_that_might_error() except Exception as error: logger.debug(traceback.format_exc()) |
哪些日志:
1 2 3 4 5 | DEBUG:__main__:Traceback (most recent call last): File"<stdin>", line 2, in <module> File"<stdin>", line 2, in do_something_that_might_error File"<stdin>", line 2, in raise_error RuntimeError: something bad happened! |
结论
对于这三个选项,我们看到我们得到的输出与出现错误时相同:
1 2 3 4 5 6 | >>> do_something_that_might_error() Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 2, in do_something_that_might_error File"<stdin>", line 2, in raise_error RuntimeError: something bad happened! |
除了@aron hall的答案外,如果您正在登录,但不想使用
1 2 3 4 | try: do_something_that_might_error() except Exception: logger.info('General exception noted.', exc_info=True) |
要获取精确的堆栈跟踪(作为字符串),如果没有try/except可以跳过它,则会引发该跟踪,只需将其放在捕获异常的except块中。
1 | desired_trace = traceback.format_exc(sys.exc_info()) |
以下是如何使用它(假设定义了
1 2 3 4 5 6 7 8 9 10 | import traceback import sys try: flaky_func() except KeyboardInterrupt: raise except Exception: desired_trace = traceback.format_exc(sys.exc_info()) log(desired_trace) |
捕获并重新提升
您需要将try/except放在可能发生错误的最内部的loop中,即
1 2 3 4 5 6 7 8 9 10 11 | for i in something: for j in somethingelse: for k in whatever: try: something_complex(i, j, k) except Exception, e: print e try: something_less_complex(i, j) except Exception, e: print e |
…等等
换言之,您需要将可能在try/except中失败的语句包装在尽可能多的内部循环中,尽可能具体。
首先,不要使用
第二,当存在本机的简单方法时,不要被诱惑去使用不相关的工具。这里是:
1 2 3 4 5 6 | log = logging.getLogger(__name__) try: call_code_that_fails() except MyError: log.exception('Any extra info you want to see in your logs') |
就是这样。你现在完了。
对事情如何发展感兴趣的人的解释好吧,这里有一些考虑:
- 这是正确的;
- 这是直截了当的;
- 这很简单。
为什么没有人不应该使用
嗯,因为!它们都是为了不同的目的而存在的。例如,
把
你一定要尽量避免和
关于这个答案的评论:
Traceback (most recent call last):
File"C:\Users\User\Desktop\test.py", line 7, in
hell do_stuff()
File"C:\Users\User\Desktop\test.py", line 4, in do_stuff
1/0
ZeroDivisionError: integer division or modulo by zero
o
[Finished in 0.1s]
所以我用:
1 2 3 4 5 6 7 8 9 10 | import traceback, sys def do_stuff(): 1/0 try: do_stuff() except Exception: print(traceback.format_exc()) print('hello') |
您需要跟踪模块。它将允许您像Python一样打印堆栈转储。特别是,print_last函数将打印最后一个异常和堆栈跟踪。