我想在不退出的情况下捕获和记录异常,例如,
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/,只是拦截异常,并且我不希望它退出程序。
当前回答
Python 3解决方案
stacktrace_helper.py:
from linecache import getline
import sys
import traceback
def get_stack_trace():
exc_type, exc_value, exc_tb = sys.exc_info()
trace = traceback.format_stack()
trace = list(filter(lambda x: ("\\lib\\" not in x and "/lib/" not in x and "stacktrace_helper.py" not in x), trace))
ex_type = exc_type.__name__
ex_line = exc_tb.tb_lineno
ex_file = exc_tb.tb_frame.f_code.co_filename
ex_message = str(exc_value)
line_code = ""
try:
line_code = getline(ex_file, ex_line).strip()
except:
pass
trace.insert(
0, f'File "{ex_file}", line {ex_line}, line_code: {line_code} , ex: {ex_type} {ex_message}',
)
return trace
def get_stack_trace_str(msg: str = ""):
trace = list(get_stack_trace())
trace_str = "\n".join(list(map(str, trace)))
trace_str = msg + "\n" + trace_str
return trace_str
其他回答
除了Aaron Hall的回答之外,如果您正在记录日志,但不想使用logging.exception()(因为它在ERROR级别记录日志),您可以使用更低的级别并传递exc_info=True。如。
try:
do_something_that_might_error()
except Exception:
logging.info('General exception noted.', exc_info=True)
在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/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/中失败的语句包装在尽可能具体的内部循环中。
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中测试
我在其他答案中没有看到这个。如果你出于某种原因传递一个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')
注意,堆栈打印是不同的,第一行和最后一行都不见了。因为它是不同的格式()。
在尽可能远离异常引发点的地方拦截异常,可以简化代码,同时提供更多信息。