我想在不退出的情况下捕获和记录异常,例如,
try:
do_stuff()
except Exception as err:
print(Exception, err)
# I want to print the entire traceback here,
# not just the exception name and details
我想打印与抛出异常时打印的完全相同的输出,而不使用try/,只是拦截异常,并且我不希望它退出程序。
我想在不退出的情况下捕获和记录异常,例如,
try:
do_stuff()
except Exception as err:
print(Exception, err)
# I want to print the entire traceback here,
# not just the exception name and details
我想打印与抛出异常时打印的完全相同的输出,而不使用try/,只是拦截异常,并且我不希望它退出程序。
当前回答
在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--------')
输出如下所示:
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--------
其他回答
你可以这样做:
try:
do_stuff()
except Exception, err:
print(Exception, err)
raise err
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()
首先,不要使用打印来记录日志,有一个稳定的、经过验证的、经过深思熟虑的stdlib模块可以做到这一点:日志。你绝对应该用它来代替。
其次,当有原生的简单方法时,不要试图用不相关的工具搞得一团糟。下面就是:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
就是这样。现在你完成了。
为任何对事物的工作原理感兴趣的人提供解释
什么日志。异常实际上所做的只是对日志的调用。error(即记录级别为error的事件),然后打印traceback。
为什么更好呢?
这里有一些注意事项:
它刚刚好; 这很简单; 这很简单。
为什么没有人应该使用exc_info=True的跟踪或调用记录器,或者用sys.exc_info弄脏他们的手?
嗯,就是因为!它们存在的目的各不相同。例如,traceback。Print_exc的输出与解释器本身产生的回溯略有不同。如果你使用它,你会让任何阅读你日志的人感到困惑,他们会用头去撞你的日志。
将exc_info=True传递给日志调用是不合适的。但是,当捕获可恢复的错误并且你想用回溯记录它们(使用,例如INFO级别)时,它是有用的,因为log。exception只产生一个级别的日志- ERROR。
而且你绝对应该避免和sys搞混。Exc_info。它不是一个公共接口,而是一个内部接口——如果你明确知道自己在做什么,你就可以使用它。它不仅仅用于打印异常。
traceback.format_exception (exception_object)
如果你只有异常对象,你可以从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_obj = 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.9/library/traceback.html traceback.format_exception
请参见:从异常对象中提取回溯信息
在Python 3.9中测试
其他一些答案已经指出了回溯模块。
请注意,使用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!
但这也有一些陷阱:
From the doc of 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) but, from the same doc: 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产生了一个不那么令人惊讶的结果:
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!")