我想在不退出的情况下捕获和记录异常,例如,
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/,只是拦截异常,并且我不希望它退出程序。
当前回答
我在其他答案中没有看到这个。如果你出于某种原因传递一个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')
注意,堆栈打印是不同的,第一行和最后一行都不见了。因为它是不同的格式()。
在尽可能远离异常引发点的地方拦截异常,可以简化代码,同时提供更多信息。
其他回答
除了Aaron Hall的回答之外,如果您正在记录日志,但不想使用logging.exception()(因为它在ERROR级别记录日志),您可以使用更低的级别并传递exc_info=True。如。
try:
do_something_that_might_error()
except Exception:
logging.info('General exception noted.', exc_info=True)
首先,不要使用打印来记录日志,有一个稳定的、经过验证的、经过深思熟虑的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。它不是一个公共接口,而是一个内部接口——如果你明确知道自己在做什么,你就可以使用它。它不仅仅用于打印异常。
我在其他答案中没有看到这个。如果你出于某种原因传递一个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')
注意,堆栈打印是不同的,第一行和最后一行都不见了。因为它是不同的格式()。
在尽可能远离异常引发点的地方拦截异常,可以简化代码,同时提供更多信息。
如果你已经有了一个Error对象,并且你想打印整个东西,你需要做这个有点尴尬的调用:
import traceback
traceback.print_exception(type(err), err, err.__traceback__)
没错,print_exception接受三个位置参数:异常的类型、实际的异常对象和异常自身的内部回溯属性。
在python 3.5或更高版本中,类型(err)是可选的…但它是一个位置参数,所以你仍然需要显式地在它的位置传递None。
traceback.print_exception(None, err, err.__traceback__)
我不知道为什么所有这些不只是traceback.print_exception(err)。为什么你会想打印出一个错误,以及一个回溯,而不是属于该错误的,这超出了我的理解。
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])