我正在编写一个程序,该程序可以解析10个网站,找到数据文件,保存文件,然后解析它们以生成可以在NumPy库中轻松使用的数据。 有过不良链接,不好的XML,缺项,其他的事情我还没有进行分类文件遭遇吨的错误。 我最初制作该程序来处理以下错误:
try:
do_stuff()
except:
pass
但是现在我想记录错误:
try:
do_stuff()
except Exception, err:
print Exception, err
请注意,这是打印到日志文件以供以后查看。 这通常会打印非常无用的数据。 我想要的是在错误触发时打印完全相同的行,而没有try-except拦截异常,但是我不希望它暂停我的程序,因为它嵌套在我想要的一系列for循环中看到完成。
#1楼
其他一些答案已经指出了追溯模块。
请注意,使用print_exc
,在某些print_exc
情况下,您将无法获得预期的结果。 在Python 2.x中:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
...将显示最后一个异常的回溯:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
如果您确实需要访问原始的追溯,一种解决方案是将exc_info
返回的异常信息缓存在本地变量中,并使用print_exception
显示它:
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
生产:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
很少有这个陷阱:
从
sys_info
的文档中:在处理异常的函数中将回溯返回值分配给局部变量将导致循环引用 。 这将防止垃圾回收由同一函数中的局部变量或回溯引用的任何内容。 [...] 如果确实需要回溯,请确保在使用后将其删除 (最好通过try ... finally语句完成)
但是,根据同一文档:
从Python 2.2开始,启用垃圾收集并使其无法访问时, 会自动回收此类循环 ,但是避免创建循环仍然更加有效。
另一方面,通过允许您访问与异常关联的回溯,Python 3产生了一个不太令人惊讶的结果:
import traceback
try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_tb(err.__traceback__)
...将显示:
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
#2楼
如果您正在调试,并且只想查看当前的堆栈跟踪,则可以简单地调用:
无需为了再次捕获而手动引发异常。
#3楼
如何在不停止程序的情况下打印完整的回溯?
当您不想因错误而暂停程序时,需要使用try / except处理该错误:
try:
do_something_that_might_error()
except Exception as error:
handle_the_error(error)
要提取完整的追溯,我们将使用标准库中的traceback
模块:
import traceback
并创建一个相当复杂的堆栈跟踪以演示我们获得了完整的堆栈跟踪:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
列印
要打印完整的回溯,请使用traceback.print_exc
方法:
try:
do_something_that_might_error()
except Exception as error:
traceback.print_exc()
哪些打印:
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!
比打印,记录更好:
但是,最佳实践是为模块设置一个记录器。 它将知道模块的名称,并能够更改级别(在其他属性中,例如处理程序)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
在这种情况下,您需要使用logger.exception
函数:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
哪个日志:
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!
或者,也许您只需要字符串,在这种情况下,您将需要traceback.format_exc
函数:
try:
do_something_that_might_error()
except Exception as error:
logger.debug(traceback.format_exc())
哪个日志:
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!
结论
对于这三个选项,我们看到的输出与发生错误时的输出相同:
>>> 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!
#4楼
为了获得精确的堆栈跟踪,作为一个字符串, 本来如果没有尝试/除非在那里步过它,只是把这个在除块捕获违规的异常上升。
desired_trace = traceback.format_exc(sys.exc_info())
这是使用方法(假设已定义flaky_func
,并且log
调用了您喜欢的日志系统):
import traceback
import sys
try:
flaky_func()
except KeyboardInterrupt:
raise
except Exception:
desired_trace = traceback.format_exc(sys.exc_info())
log(desired_trace)
捕获并重新引发KeyboardInterrupt
是一个好主意,这样您仍然可以使用Ctrl-C终止程序。 日志记录不在问题的范围内,但是很好的选择是logging 。 sys和traceback模块的文档。
#5楼
您需要将try / except放到可能发生错误的最内层循环中,即
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中失败的语句包装在尽可能多的内部循环中,并尽可能不具体。
#6楼
您需要回溯模块。 它可以让您像Python通常一样打印堆栈转储。 特别是, print_last函数将打印最后的异常和堆栈跟踪。
#7楼
如果那是您想要的, traceback.format_exc()
或sys.exc_info()
将产生更多信息。
import traceback
import sys
try:
do_stuff()
except Exception:
print(traceback.format_exc())
# or
print(sys.exc_info()[2])
#8楼
除了@Aaron Hall的答案外,如果您正在记录日志,但又不想使用logging.exception()
(因为它以ERROR级别记录),则可以使用较低级别并传递exc_info=True
。 例如
try:
do_something_that_might_error()
except Exception:
logger.info('General exception noted.', exc_info=True)
#9楼
关于此答案的评论: print(traceback.format_exc())
对我来说比traceback.print_exc()
更好。 对于后者, hello
有时会奇怪地与回溯文本“混合”,例如,如果两者都想同时写入stdout或stderr,则产生奇怪的输出(至少在从文本编辑器内部进行构建并在其中查看输出时)。 “构建结果”面板)。
追溯(最近一次通话):
在第7行的文件“ C:\\ Users \\ User \\ Desktop \\ test.py”
地狱 do_stuff()
文件“ C:\\ Users \\ User \\ Desktop \\ test.py”,行4,位于do_stuff中
1/0
ZeroDivisionError:整数除法或以零为模
Ø
[以0.1秒完成]
所以我用:
import traceback, sys
def do_stuff():
1/0
try:
do_stuff()
except Exception:
print(traceback.format_exc())
print('hello')
#10楼
首先,不要使用print
进行日志记录,有一个稳定,经过验证且经过深思熟虑的stdlib模块可以做到这一点: logging
。 您绝对应该改用它。
其次,当存在本机且简单的方法时,不要试图将无关的工具弄得一团糟 。 这里是:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
而已。 现在完成了。
对任何对引擎盖如何工作感兴趣的人的解释
log.exception
实际在执行的只是对log.error
的调用(即,级别为ERROR
日志事件) ,然后打印回溯。
为什么会更好?
好,这是一些注意事项:
- 这是正确的 ;
- 这很简单;
- 很简单。
为什么没人应该使用traceback
或用exc_info=True
调用记录器,或者不使用sys.exc_info
弄脏他们的手?
好吧,只是因为! 它们全都出于不同的目的而存在。 例如, traceback.print_exc
的输出与解释器本身产生的追溯有些不同。 如果您使用它,将会使任何人阅读您的日志感到困惑,他们会将头撞向他们。
传递exc_info=True
进行日志调用是不合适的。 但是 ,捉可恢复的错误时,它是有用的,要记录他们(例如使用INFO
等级)与回溯为好,因为log.exception
只产生一个级别的日志- ERROR
。
而且,您绝对应该尽可能避免使sys.exc_info
混乱。 它不是一个公共接口,而是一个内部接口-如果您完全知道自己在做什么,就可以使用它。 它不仅仅用于打印例外。
#11楼
获得完整回溯从与异常对象的字符串traceback.format_exception
如果只有异常对象,则可以使用以下命令从Python 3中的代码的任何点以字符串形式获取跟踪:
import traceback
''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
完整示例:
#!/usr/bin/env python3
import traceback
def f():
g()
def g():
raise Exception('asdf')
try:
g()
except Exception as e:
exc = e
tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)
输出:
Traceback (most recent call last):
File "./main.py", line 12, in <module>
g()
File "./main.py", line 9, in g
raise Exception('asdf')
Exception: asdf
文档: https : //docs.python.org/3.7/library/traceback.html#traceback.format_exception
另请参阅: 从异常对象中提取回溯信息
在Python 3.7.3中测试。
#12楼
我在其他任何答案中都没有提到这一点。 如果出于任何原因要传递Exception对象...
在Python 3.5+中,您可以使用traceback.TracebackException.from_exception()从Exception对象获取跟踪 。 例如:
import traceback
def stack_lvl_3():
raise Exception('a1', 'b2', 'c3')
def stack_lvl_2():
try:
stack_lvl_3()
except Exception as e:
# raise
return e
def stack_lvl_1():
e = stack_lvl_2()
return e
e = stack_lvl_1()
tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))
但是,以上代码导致:
Traceback (most recent call last):
File "exc.py", line 10, in stack_lvl_2
stack_lvl_3()
File "exc.py", line 5, in stack_lvl_3
raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')
这只是堆栈的两个级别,与如果在stack_lvl_2()
引发异常并且未拦截该异常(取消注释# raise
行)相比,在屏幕上所打印的内容相反。
据我了解,这是因为异常在引发时仅记录堆栈的当前级别,在这种情况下为stack_lvl_3()
。 随着它在堆栈中的传递,它的__traceback__
被添加了更多的层次。 但是我们在stack_lvl_2()
截获了它,这意味着它要记录的仅是3级和2级。要获得在stdout上打印的完整跟踪,我们必须在最高(最低?)级捕获它:
import traceback
def stack_lvl_3():
raise Exception('a1', 'b2', 'c3')
def stack_lvl_2():
stack_lvl_3()
def stack_lvl_1():
stack_lvl_2()
try:
stack_lvl_1()
except Exception as exc:
tb = traceback.TracebackException.from_exception(exc)
print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))
结果是:
Handled at stack lvl 0
File "exc.py", line 17, in <module>
stack_lvl_1()
File "exc.py", line 13, in stack_lvl_1
stack_lvl_2()
File "exc.py", line 9, in stack_lvl_2
stack_lvl_3()
File "exc.py", line 5, in stack_lvl_3
raise Exception('a1', 'b2', 'c3')
注意,堆栈打印不同,缺少第一行和最后一行。 因为它是不同的format()
。
截取该异常离生成点越远越好,这可以简化代码,同时提供更多信息。
#13楼
一个班轮:
import traceback
traceback.print_exc()
使用traceback
模块,该模块在以下内容中自动获取当前异常except:
https://stackoverflow.com/a/9555145/2217801
#14楼
如果您已经有一个Error对象,并且想要打印整个内容,则需要进行此稍显尴尬的调用:
import traceback
traceback.print_exception(type(err), err, err.__traceback__)
没错, print_exception
具有三个位置参数:异常的类型,实际的异常对象以及异常自己的内部回溯属性。
在python 3.5或更高版本中, type(err)
是可选的...但是它是一个位置参数,因此您仍然必须在其位置显式传递None。
traceback.print_exception(None, err, err.__traceback__)
我不知道为什么所有这些都不只是traceback.print_exception(err)
。 为什么您要打印出错误以及与该错误无关的回溯,这超出了我的范围。