chr*_*ley 696 python exception-handling
我正在编写一个程序来解析10个网站,查找数据文件,保存文件,然后解析它们以生成可以在NumPy库中使用的数据.有吨的错误该文件通过遇到不良链接,不好的XML,缺项,其他的事情我还没有进行分类.我最初制作这个程序来处理这样的错误:
try:
do_stuff()
except:
pass
Run Code Online (Sandbox Code Playgroud)
但现在我想记录错误:
try:
do_stuff()
except Exception, err:
print Exception, err
Run Code Online (Sandbox Code Playgroud)
请注意,这是打印到日志文件以供以后查看.这通常会打印非常无用的数据.我想要的是打印错误触发时打印的完全相同的行,没有try-except拦截异常,但我不希望它暂停我的程序,因为它嵌套在一系列for循环中,我想看完成了.
vol*_*ing 661
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])
Run Code Online (Sandbox Code Playgroud)
Syl*_*oux 515
其他一些答案已经指出了追溯模块.
请注意print_exc,在某些角落的情况下,您将无法获得您期望的结果.在Python 2.x中:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
Run Code Online (Sandbox Code Playgroud)
...将显示最后一个异常的回溯:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
Run Code Online (Sandbox Code Playgroud)
如果您确实需要访问原始回溯,一个解决方案是缓存从局部变量返回的异常信息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
Run Code Online (Sandbox Code Playgroud)
生产:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
Run Code Online (Sandbox Code Playgroud)
尽管如此,很少有陷阱:
来自以下文件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__)
Run Code Online (Sandbox Code Playgroud)
...将显示:
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
Run Code Online (Sandbox Code Playgroud)
dim*_*414 223
如果您正在调试并且只想查看当前堆栈跟踪,则只需调用:
没有必要手动引发异常只是为了再次捕获它.
Aar*_*all 86
如何在不停止程序的情况下打印完整的回溯?
如果您不想在出错时暂停程序,则需要使用try/except来处理该错误:
try:
do_something_that_might_error()
except Exception as error:
handle_the_error(error)
Run Code Online (Sandbox Code Playgroud)
要提取完整的回溯,我们将使用traceback标准库中的模块:
import traceback
Run Code Online (Sandbox Code Playgroud)
并创建一个相当复杂的堆栈跟踪来演示我们获得完整的堆栈跟踪:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
Run Code Online (Sandbox Code Playgroud)
要打印完整的回溯,请使用以下traceback.print_exc方法:
try:
do_something_that_might_error()
except Exception as error:
traceback.print_exc()
Run Code Online (Sandbox Code Playgroud)
哪个印刷品:
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!
Run Code Online (Sandbox Code Playgroud)
但是,最佳做法是为模块设置记录器.它将知道模块的名称并能够更改级别(以及其他属性,例如处理程序)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将需要该logger.exception功能:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
Run Code Online (Sandbox Code Playgroud)
哪些日志:
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!
Run Code Online (Sandbox Code Playgroud)
或者你可能只想要字符串,在这种情况下,你会想要这个traceback.format_exc函数:
try:
do_something_that_might_error()
except Exception as error:
logger.debug(traceback.format_exc())
Run Code Online (Sandbox Code Playgroud)
哪些日志:
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!
Run Code Online (Sandbox Code Playgroud)
对于所有三个选项,我们看到输出与出错时相同:
>>> 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!
Run Code Online (Sandbox Code Playgroud)
sou*_*ole 23
在 python3(适用于 3.9)中,我们可以定义一个函数,并可以在我们想要打印详细信息的地方使用它。
import traceback
def get_traceback(e):
lines = traceback.format_exception(type(e), e, e.__traceback__)
return ''.join(lines)
try:
1/0
except Exception as e:
print('------Start--------')
print(get_traceback(e))
print('------End--------')
try:
spam(1,2)
except Exception as e:
print('------Start--------')
print(get_traceback(e))
print('------End--------')
Run Code Online (Sandbox Code Playgroud)
输出如下:
bash-3.2$ python3 /Users/soumyabratakole/PycharmProjects/pythonProject/main.py
------Start--------
Traceback (most recent call last):
File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 26, in <module>
1/0
ZeroDivisionError: division by zero
------End--------
------Start--------
Traceback (most recent call last):
File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 33, in <module>
spam(1,2)
NameError: name 'spam' is not defined
------End--------
Run Code Online (Sandbox Code Playgroud)
Cir*_*四事件 19
traceback.format_exception(exception_object)
如果您只有异常对象,则可以使用以下命令从 Python 3 中的任何代码点以字符串形式获取回溯:
import traceback
''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
Run Code Online (Sandbox Code Playgroud)
完整示例:
#!/usr/bin/env python3
import traceback
def f():
g()
def g():
raise Exception('asdf')
try:
g()
except Exception as e:
exc_obj = e
tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
文档:https : //docs.python.org/3.9/library/traceback.html#traceback.format_exception
另请参阅:从异常对象中提取回溯信息
在 Python 3.9 中测试
bgd*_*nlp 17
我在其他任何答案中都没有看到这一点。如果您出于任何原因传递 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()))
Run Code Online (Sandbox Code Playgroud)
但是,上面的代码导致:
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')
Run Code Online (Sandbox Code Playgroud)
这只是堆栈的两个级别,而不是在屏幕上打印的内容,如果异常被引发stack_lvl_2()而不被拦截(取消注释该# raise行)。
据我了解,这是因为stack_lvl_3()在这种情况下,异常仅记录引发时堆栈的当前级别。当它通过堆栈向上传递时,更多的级别被添加到它的__traceback__. 但是我们在 中截获了它stack_lvl_2(),这意味着它要记录的只是级别 3 和 2。要获得打印在标准输出上的完整跟踪,我们必须在最高(最低?)级别捕获它:
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()))
Run Code Online (Sandbox Code Playgroud)
结果是:
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')
Run Code Online (Sandbox Code Playgroud)
请注意,堆栈打印不同,缺少第一行和最后一行。因为它是不同的format()。
尽可能远离引发异常的点拦截异常可以使代码更简单,同时也提供更多信息。
tos*_*osh 16
首先,不要用printS表示日志记录,有非稳态,证明和深思熟虑的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')
Run Code Online (Sandbox Code Playgroud)
而已。现在完成了。
什么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。它不是一个公共接口,而是一个内部接口- 如果您完全知道自己在做什么,就可以使用它。它不仅仅用于打印例外。
除了@Aaron霍尔的答案,如果你正在登录,但不希望使用logging.exception()(因为它记录在错误级别),你可以用一个较低的水平,并通过exc_info=True.例如
try:
do_something_that_might_error()
except Exception:
logger.info('General exception noted.', exc_info=True)
Run Code Online (Sandbox Code Playgroud)
import io
import traceback
try:
call_code_that_fails()
except:
errors = io.StringIO()
traceback.print_exc(file=errors) # Instead of printing directly to stdout, the result can be further processed
contents = str(errors.getvalue())
print(contents)
errors.close()
Run Code Online (Sandbox Code Playgroud)
为了得到精确的堆栈跟踪,作为一个字符串,将在没有尝试/除非在那里跨过它,只需将这种在不同的块捕获违规的异常已经提出.
desired_trace = traceback.format_exc(sys.exc_info())
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它(假设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)
Run Code Online (Sandbox Code Playgroud)
捕获并重新引发KeyboardInterrupts 是个好主意,这样你仍然可以使用Ctrl-C终止程序.记录超出了问题的范围,但一个很好的选择是记录.sys和traceback模块的文档.
您需要将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
Run Code Online (Sandbox Code Playgroud)
... 等等
换句话说,您需要在尽可能具体的情况下尽可能地包装try/except中可能失败的语句.
关于此答案的评论:print(traceback.format_exc())与相比,对我来说做得更好traceback.print_exc()。对于后者,hello有时会奇怪地将其与回溯文本“混合”,例如,如果两者都想同时写入stdout或stderr,则会产生奇怪的输出(至少在文本编辑器内部进行构建并在“构建结果”面板)。
追溯(最近一次通话):
文件“ C:\ Users \ User \ Desktop \ test.py”,第7行,在
地狱 do_stuff()
文件“ C:\ Users \ User \ Desktop \ test.py”,第4行,在do_stuff
1/0
ZeroDivisionError中:整数除或以零为模的
o
[在0.1s内完成]
所以我用:
import traceback, sys
def do_stuff():
1/0
try:
do_stuff()
except Exception:
print(traceback.format_exc())
print('hello')
Run Code Online (Sandbox Code Playgroud)
如果您已经有一个 Error 对象,并且您想打印整个内容,则需要进行这个有点尴尬的调用:
import traceback
traceback.print_exception(type(err), err, err.__traceback__)
Run Code Online (Sandbox Code Playgroud)
没错,print_exception需要三个位置参数:异常的类型、实际的异常对象和异常自己的内部回溯属性。
在 python 3.5 或更高版本中, thetype(err)是可选的...但它是一个位置参数,因此您仍然必须在其位置显式传递 None 。
traceback.print_exception(None, err, err.__traceback__)
Run Code Online (Sandbox Code Playgroud)
我不知道为什么所有这些不只是traceback.print_exception(err). 为什么你会想要打印出一个错误,以及一个不是属于那个错误的回溯,这超出了我的理解。
此答案中的这种用法是自 Python 3.10 以来的新用法,并且尚未被任何先前的答案涵盖。要打印回溯,可以将异常赋予traceback.print_exception.
例子:
import traceback
try:
object.bad_attr
except Exception as exc:
traceback.print_exception(exc)
Run Code Online (Sandbox Code Playgroud)
输出回溯:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: type object 'object' has no attribute 'bad_attr'
Run Code Online (Sandbox Code Playgroud)
提醒一下,这个答案需要 Python 3.10 或更高版本才能起作用。
要将引用捕获为字符串,请参阅此答案。
| 归档时间: |
|
| 查看次数: |
606991 次 |
| 最近记录: |